[silverstripe-dev] Upgrading Site Search Functionality

350 views
Skip to first unread message

webbower

unread,
May 14, 2010, 1:31:02 PM5/14/10
to SilverStripe Core Development
HI all,

I'm beginning development of an improved internal search engine system
for SS. The one that comes with the core is a little limited in my
opinion. This project is spurred on by a current client project where
I need 2 different search forms: 1 that searches the whole site and 1
that searches just a specific section (the site's forum). I also need
the site search form to search DataObjects that aren't subclasses of
SiteTree or File like is hard-coded in the current search
functionality.

The goals of the new search functionality:
* Provide a simple API to create custom "search engines" that allow
you to search with different criteria (limit to a section, choose
specific DataObject subclasses to search, etc)
* Make it so ANY DataObject subclass is searchable and can be listed
in the results
* Provide base class(es) to create custom search forms: from a basic
search form with just a text field and submit button to an "advanced"
search form with any number of additional options (checkboxes,
dropdowns, etc) that are each tied to one or more DO columns to
search.
* When you create the "SearchForm" method in your controller class
that return the form, you tie one of the custom "search engines" to it
so it uses that search engine. This way you can have custom search
forms throughout your website that are each powered by a different
engine.

What are people's thoughts on this?

A question directly to the SS core team: Are you guys working on
upgrading the bundled search functionality anytime soon? If not, I
would like to propose my end result be included in the core to replace
the existing search feature if you approve of it.

Thanks everyone!

Matt Bower

--
You received this message because you are subscribed to the Google Groups "SilverStripe Core Development" group.
To post to this group, send email to silverst...@googlegroups.com.
To unsubscribe from this group, send email to silverstripe-d...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/silverstripe-dev?hl=en.

SmartPlugsDesign

unread,
May 14, 2010, 1:41:06 PM5/14/10
to SilverStripe Core Development
Hi Matt-

This sounds great... I know I could definitely use this in my
projects. What is your projected timeline?

-John

Marcus Nyeholt

unread,
May 14, 2010, 1:44:59 PM5/14/10
to silverst...@googlegroups.com
I've been toying with the idea of putting together some documentation about how the search mechanism could be revamped - the motivation behind this being that I've just about got a release ready for an integration with Solr (http://github.com/nyeholt/silverstripe-solr/tree/development - it's still in active dev though, and there's little documentation just yet), and I know the NZ guys have been working on an integration with Sphinx. While these are search backends, there should be a suitable interface between controller level code and any kind of search backend. 

So far for the Solr integration I've created a very simple SearchPage type, which doesn't really do much at the moment but is more of a placeholder until I get around to thinking further about how would be the best way to work it in with all the different search backends to interact with it. Now might be the time to think more about it :)

Marcus

Matt Bower

unread,
May 14, 2010, 2:03:51 PM5/14/10
to silverst...@googlegroups.com
Well, since it looks like I need it for a current project as the built in search functionality for the core and Forum modules is not doing what I need, pretty soon. A month maybe for a first release.

Matt Bower

unread,
May 14, 2010, 2:15:44 PM5/14/10
to silverst...@googlegroups.com
It looks like the difference between your Solr tie-in and the Sphinx tie-in modules is that they are going to be single purpose. My goal is to build a customizable framework for making custom search engines using the easy-to-use SS framework that is already there.

Now that you bring up the topic of existing powerful search engine systems like them, I will add another goal to my new search engine system for SS: the ability to easily tie-in external search engine systems like Solr and Sphinx. This feature will probably not be in my initial release since the initial release will be based on what I need for this client project of mine. Plus, I haven't used anything like Solr or Sphinx yet so I'll need to do some research. Help from people who have experience with libraries like those will be helpful since that will reduce how much research I'll need to do. That way, SS will be able to have a flexible search framework where one can write their own engines or tie-in those libraries, all using the same SS API.

In writing this response, another feature goal has come to mind. So, 2 new feature goals after this email (both will probably not be included in the initial release, but in later versions):
* The ability to tie-in existing powerful search engine libraries like Solr, Sphinx, and more
* The ability to easily define search query modifiers. Think Google: "+keyword" makes it so that keyword MUST be in each result; "-keyword" makes it so the keyword should NOT be present in any of the results, etc

Simon J Welsh

unread,
May 14, 2010, 4:34:38 PM5/14/10
to silverst...@googlegroups.com
How does this compare with SearchContext?
> To post to this group, send email to silverstripe-
> d...@googlegroups.com.
> To unsubscribe from this group, send email to silverstripe-d...@googlegroups.com
> .
> For more options, visit this group at http://groups.google.com/group/silverstripe-dev?hl=en
> .
>

---
Simon Welsh
Admin of http://simon.geek.nz/

Who said Microsoft never created a bug-free program? The blue screen
never, ever crashes!

http://www.thinkgeek.com/brain/gimme.cgi?wid=81d520e5e

Matt Bower

unread,
May 14, 2010, 9:24:15 PM5/14/10
to silverst...@googlegroups.com
Not sure. Didn't know about SearchContext until I was researching how to build this system. I'll get back to you on that one once I know that answer myself.

malte@eos

unread,
May 17, 2010, 3:23:03 AM5/17/10
to SilverStripe Core Development
Hi Matt,

a while ago, I created a pretty simple search.

1. Extend the SearchForm (see EOSSearchForm.php)
2. Implement the interface in your DataObject (see
SearchableDataObject.php)
3. Put this line in your _config.php: EOSSearchForm::
$DataObjectsToSearch = array('SiteTree', 'ArticleDataObject');
4. Create your SearchForm in the Page-Controller
5. Modify your Page_results.ss to your needs. E.g. create a different
list entry (check for the ClassName) for each DataObject you want to
use. So you can have somthing like "Goto Page", "Goto Article", etc

You can do anything you want with this code as long as you keep the
author and the link in the phpdoc-comment ;)

Cheers,

Malte

------
EOSSearchForm.php
<?php
/**
* @fixme Description
* @fixme Description of method params!
*
* @package eos_basics
* @subpackage forms
* @author Malte Jansen, EOS Uptrade GmbH, Germany <development@eos-
uptrade.de>
* @link http://www.eos-uptrade.de/silverstripe/
*/
class EOSSearchForm extends SearchForm {

protected $classesToSearchCache = NULL;

public static $DataObjectsToSearch = array();

/**
* The core search engine, used by this class and its subclasses to
do fun stuff.
* Searches both SiteTree and File.
*
* @param string $keywords Keywords as a string.
*/
public function searchEngine($keywords, $pageLength = null, $sortBy =
"Relevance DESC", $extraFilter = "", $booleanSearch = false,
$alternativeFileFilter = "", $invertedMatch = false) {
if (!$pageLength) $pageLength = $this->pageLength;
$fileFilter = '';
$keywords = trim($keywords);
if (empty($keywords)) {
return new DataObjectSet();
}
$keywords = addslashes($keywords);

$extraFilters = $this->getExtraFilters();

if ($booleanSearch) $boolean = "IN BOOLEAN MODE";
if ($extraFilter) {
$extraFilters['SiteTree'] = " AND $extraFilter";

if ($alternativeFileFilter)
$extraFilters['File'] = " AND $alternativeFileFilter";
else
$extraFilters['File'] = $extraFilters['SiteTree'];
}


$start = isset($_GET['start']) ? (int)$_GET['start'] : 0;
$limit = $start . ", " . (int) $pageLength;

$notMatch = $invertedMatch ? "NOT " : "";
if($keywords) {
$match = $this->getMatch($keywords, $boolean);

// We make the relevance search by converting a boolean mode
// search into a normal one
$relevanceKeywords = str_replace(array('*','+','-'),'',$keywords);
$relevance = $this->getRelevance($relevanceKeywords);
} else {
$match = array();
$relevance = array();
foreach ($this->getClassesToSearch() AS $ClassNameToSearch) {
$relevance[$ClassNameToSearch] = 1;
$match[$ClassNameToSearch] = "1 = 1";
}
}

// Generate initial queries and base table names
foreach($this->getClassesToSearch() as $class => $value) {
$queries[$class] = singleton($class)->extendedSQL($notMatch .
$match[$class] . $extraFilters[$class],"");
$baseClasses[$class] = reset($queries[$class]->from);
}

// Make column selection lists
$select = $this->getSelect($baseClasses, $relevance);

// Process queries
foreach($this->getClassesToSearch() as $class => $value) {
// There's no need to do all that joining
$queries[$class]->from = array(str_replace('`','',
$baseClasses[$class]) => $baseClasses[$class]);
$queries[$class]->select = $select[$class];
$queries[$class]->orderby = null;
// echo $class."<br />".$queries[$class]."<br /><br />";
}

// Combine queries
$querySQLs = array();
$totalCount = 0;
foreach($queries as $query) {
$querySQLs[] = $query->sql();
$totalCount += $query->unlimitedRowCount();
}
$fullQuery = implode(" UNION ", $querySQLs) .
" ORDER BY $sortBy LIMIT $limit";

// Get records
$records = DB::query($fullQuery);

$objects = array();
foreach($records as $record) {
$object = DataObject::get_by_id($record['ClassName'],
$record['ID']);
if (is_a($object, 'ContentDataObject')) {
$object->setExternalLinkData(NULL, TRUE);
}
$objects[] = $object;
}

if(count($objects) > 0) {
$doSet = new DataObjectSet($objects);
$doSet->setPageLimits($start, $pageLength, $totalCount);
return $doSet;
}
return new DataObjectSet();
}

/**
*
*
* @param object $relevanceKeywords
* @return array
*/
protected function getRelevance($relevanceKeywords) {
$relevance = $this->getClassesToSearch();
foreach ($relevance AS $className => $value) {
switch ($className) {
case 'SiteTree':
$relevance[$className] = "MATCH (Title) AGAINST
('$relevanceKeywords') + MATCH (Title, MenuTitle, Content, MetaTitle,
MetaDescription, MetaKeywords) AGAINST ('$relevanceKeywords')";
break;
case 'File':
$relevance[$className] = "MATCH (Filename, Title, Content)
AGAINST ('$relevanceKeywords')";
break;
default:
$dataObject = singleton($className);
$relevance[$className] = $dataObject-
>getSearchableRelevance($relevanceKeywords);
break;
}
}
return $relevance;
}

/**
*
*
* @param string $keywords
* @param string $boolean
* @return array(ClassName => string)
*/
protected function getMatch($keywords, $boolean) {
$match = $this->getClassesToSearch();
foreach ($match AS $className => $value) {
switch ($className) {
case 'SiteTree':
$match[$className] = "MATCH (Title, MenuTitle, Content,
MetaTitle, MetaDescription, MetaKeywords) AGAINST ('$keywords'
$boolean)";
break;
case 'File':
$match[$className] = "MATCH (Filename, Title, Content) AGAINST
('$keywords' $boolean) AND ClassName = 'File'";
break;
default:
$dataObject = DataObject::get_one($className);
if ($dataObject) {
$match[$className] = $dataObject->getSearchableMatch($keywords,
$boolean);
}
unset($dataObject);
break;
}
}
return $match;
}

/**
* Returns all additional filters
*
* @return array(ClassName => string)
*/
protected function getExtraFilters() {
$extraFilters = $this->getClassesToSearch();
foreach ($extraFilters AS $className => $value) {
switch ($className) {
case 'SiteTree':
$extraFilters[$className].= " AND showInSearch != 0";
break;
default:
$dataObject = DataObject::get_one($className);
if ($dataObject) {
$dataObjectFilters = $dataObject->getSearchableExtraFilters();
if (!is_array($dataObjectFilters)) $dataObjectFilters = (array)
$dataObjectFilters;
if (count($dataObjectFilters) > 0) {
$extraFilters[$className].= " AND (" . implode(") AND (",
$dataObjectFilters).") " ;
}
}
break;
}
}
unset($dataObject);
return $extraFilters;
}

/**
* Returns the fields for the query
*
* @param array $baseClasses
* @param array $relevance
* @return array(array of Fields)
*/
protected function getSelect($baseClasses, $relevance) {
$select = $this->getClassesToSearch();
foreach ($select AS $className => $value) {
$select[$className] =
array("ClassName","Title","{$baseClasses[$className]}.ID","{$relevance[$className]}
AS Relevance");
}
return $select;
}

/**
* Returns and calculates the property classesToSearchCache.
*
* @return array(ClassName => NULL)
*/
protected function getClassesToSearch() {
if ($this->classesToSearchCache !== NULL) return $this-
>classesToSearchCache;
$this->classesToSearchCache = Object::get_static(__CLASS__,
'DataObjectsToSearch');
$this->classesToSearchCache = array_flip($this-
>classesToSearchCache);
foreach ($this->classesToSearchCache AS $class => $value) {
$this->classesToSearchCache[$class] = NULL;
}
return $this->classesToSearchCache;
}
}

?>
---
SearchableDataObject.php
<?php
/**
* All searchable DataObjects must contain this interface to be
loaded.
*
* @package eos_basics
* @subpackage Search
* @author Malte Jansen, EOS Uptrade GmbH, Germany <development@eos-
uptrade.de>
* @link http://www.eos-uptrade.de/silverstripe/
*/
interface SearchableDataObject {

/**
* Returns a SQL-String for the relevance calculation
* e.g. "MATCH (Title) AGAINST ('$relevanceKeywords') + MATCH (Title,
MenuTitle, Content, MetaTitle, MetaDescription, MetaKeywords) AGAINST
('$relevanceKeywords')"
*
* @param string $relevanceKeywords
* @return string
*/
public function getSearchableRelevance($relevanceKeywords);

/**
* Returns a SQL-String for the match calculation
* e.g. "MATCH (Title, MenuTitle, Content, MetaTitle,
MetaDescription, MetaKeywords) AGAINST ('$keywords' $boolean)"
*
* @param string $relevanceKeywords
* @return string
*/
public function getSearchableMatch($keywords, $boolean);

/**
* Returns an Filter-Array (AND)
*
*
* @return array(string)
*/
public function getSearchableExtraFilters();

}
?>
---
For your Page-Controller:
/**
* Site search form
*/
public function SearchForm() {
global $enableSearch;
if ($enableSearch !== TRUE) {
return '';
}
$searchText = isset($_REQUEST['Search']) ? $_REQUEST['Search'] :
'Suchbegriff';
$fields = new FieldSet(
new FocusBlurTextField("Search", "Suche", $searchText)
);
$actions = new FieldSet(
#new FormAction('results', '»')
new ImageFormAction('results', 'Suchen', $this->ThemeDir() . '/
images/suchen.png')
);

return new EOSSearchForm($this, "SearchForm", $fields, $actions);
}

/**
* Process and render search results
*/
function results($data, $form){
$data = $_REQUEST;
$data['Search'] = htmlentities($data['Search'], ENT_QUOTES,
'UTF-8');
//var_dump($data['Search']);
$data = array(
'Results' => $form->getResults(),
'Query' => $form->getSearchQuery(),
'Title' => 'Search Results'
);

return $this->customise($data)->renderWith(array('Page_results',
'Page'));
> >> For more options, visit this group athttp://groups.google.com/group/silverstripe-dev?hl=en.
>
> > ---
> > Simon Welsh
> > Admin ofhttp://simon.geek.nz/
>
> > Who said Microsoft never created a bug-free program? The blue screen never, ever crashes!
>
> >http://www.thinkgeek.com/brain/gimme.cgi?wid=81d520e5e
>
> > --
> > You received this message because you are subscribed to the Google Groups "SilverStripe Core Development" group.
> > To post to this group, send email to silverst...@googlegroups.com.
> > To unsubscribe from this group, send email to silverstripe-d...@googlegroups.com.
> > For more options, visit this group athttp://groups.google.com/group/silverstripe-dev?hl=en.
>
> --
> You received this message because you are subscribed to the Google Groups "SilverStripe Core Development" group.
> To post to this group, send email to silverst...@googlegroups.com.
> To unsubscribe from this group, send email to silverstripe-d...@googlegroups.com.
> For more options, visit this group athttp://groups.google.com/group/silverstripe-dev?hl=en.

Marcus Nyeholt

unread,
May 17, 2010, 5:11:28 AM5/17/10
to silverst...@googlegroups.com
I'd suggest that this would be the best path to look down. Talking purely interfaces here, not specific implementations, I'd roughly thought along the lines of

  • User types something into a search form, hits 'search', GET request to /search or something
  • Within the SearchController, the search action creates an object that implements the SearchContext interface, which contains the various data from the GET request in relevant locations. This SearchContext would implement a method for serialising the search data to a form that can be saved (this is actually how Alfresco manages saved searches) and restored very simply
  • The search action then uses an object that implements a SearchService (or SearchEngine, or othernamehere) interface and calls performSearch(SearchContext $ctx)
  • The performSearch method returns a SearchResultSet that implements methods like as getDataObjects() (result set as data objects), getQueryString() (to retrieve a urlencoded string that can be used for perfoming this query again, useful for pagination etc) and a few other methods of that sort that all search engines will implement - obviously some will have additional features, 
Anyway, those are just some basic thoughts, anyone else want to throw anything else into the mix?

Marcus

windandwaves

unread,
May 17, 2010, 7:52:05 AM5/17/10
to SilverStripe Core Development
Hi Everyone

I dont have much time to read this thread right now but this might be
of interest to some of you:

http://sunny.svnrepository.com/svn/sunny-side-up-general/searchplus

The module allows you to add a basic search function, nothing fancy,
but it has a few nice functions:

* keep a search log (and make a list of popular searches)
* it allows you to make redirection (e.g. if you have a shop selling
widgets, but visitors search for widjets then you can setup an
automatic redirection).

Hope it is of help. Sorry that I do not have time to look at all your
postings right now.

Nicolaas

Michael Mitchell

unread,
May 17, 2010, 3:48:29 PM5/17/10
to silverst...@googlegroups.com
I've made a simple implementation using the Zend Framework library for Lucene (http://en.wikipedia.org/wiki/Lucene), it supports multiple Indices and has a lot of powerful features from Lucene Search Engine to build from (http://framework.zend.com/manual/en/zend.search.lucene.html). It is very simple to configure on a standard SS DataObject and also provides a basic controller for displaying results from the search databases.

eg...

Object::add_extension('Page', 'SearchLucene');

public static $search_lucene_fields = array(
        'Keyword' => array(),
        'UnIndexed' => array(),
        'Binary' => array(),
        'Text' => array(),
        'UnStored' => array(
            'Title' => 'Title',
            'MenuTitle' => 'MenuTitle',
            'Content' => 'Content',
            'MetaTitle' => 'MetaTitle',
            'MetaKeywords' => 'MetaKeywords',
            'MetaDescription' => 'MetaDescription'
        )
    );
   
    /**
     * default search indices
     * @var string
     */
    public static $search_lucene_indices = array(
        'pages' => 'searchLucene/index/pages',
    );
   
    /**
     * automatically write dataobject changes to the search index onAfterWrite
     * @var boolean
     */
    public static $search_lucene_auto_write = true;
   
    /**
     * automatically delete dataobjects from the search index onBeforeDelete
     * @var boolean
     */
    public static $search_lucene_auto_delete = true;


The statics can be declared on different page types to supply different functionality.. eg you might want to turn auto write off to use your own implementation to customise the text stored in the search indices.

Feel free to use and modify this as you see fit, I would be grateful if you could leave my name somewhere if you do choose to use this.

http://www.michaelmitchell.co.nz/searchLucene.zip

Kind Regards,

Michael Mitchell
Limitless Resources

Centre for Innovation
PO Box 56
Dunedin
Otago 9054
New Zealand

Phone: +64 3 453 4091
Mobile: +64 21 280 4589
Skype: michaelmitchell.co.nz

Dan | Rye Designs

unread,
May 17, 2010, 4:16:57 PM5/17/10
to silverst...@googlegroups.com
Being that so many people are solving search problems I definitely think some modules should be released on the matter.  There are a couple approaches, framework integration, or otherwise.  I'd like to see it happen.  Sorry if I'm stating the obvious, just putting my vote in for a module.  I don't see why it should be added to core, unless it can't be done with out core changes.

- Dan

Marcus Nyeholt

unread,
May 17, 2010, 9:45:53 PM5/17/10
to silverst...@googlegroups.com
The search modules themselves are definitely releaseable as is - I think the discussion is more around providing a generic platform (which could probably be done as a module that the others depend on) that those modules can be written to, to be able to provide the end user interaction aspects of search, so that the various modules can be plugged in and out. 

@Michael - Having tried the Zend Lucene implementation myself before, have you played around using a ramdisk for storing the index? I found that it was relatively slow once the index got over a trivial size - but a ramdisk solved some of those problems. 

Marcus

Sam Minnee

unread,
May 17, 2010, 10:09:45 PM5/17/10
to SilverStripe Core Development
> the NZ guys have been working on an integration with Sphinx. While these are
> search backends, there should be a suitable interface between controller
> level code and any kind of search backend.

Hamish F. and I talked about this when the Sphinx module was being
developed. The conclusion was the search engines end up having so
many different special options that beyond the form & pagination
handling that Sapphire gives you, there wasn't a lot of value in
having a unified search front-end.

In SilverStripe 2.4, we made the default search optional. sapphire/
search/ContentControllerSearchExtension.php (designed to be applied to
ContentController) provides the front-end.

The default template is designed to put $SearchForm in the top-right
corner of the page. Marcus, I would suggest you make an extension
such as SolrSearchUI that adds a SearchForm to the controller that
it's applied to.

Do you seen any problems with this approach?

Matt Bower

unread,
May 17, 2010, 10:24:17 PM5/17/10
to silverst...@googlegroups.com
You are correct Dan. Me being the person that started this thread, the goal is to make a generic search module that provides a framework for easily building custom search engines for any SS project and even the ability to make multiple search engines for a site that can focus on different datamodels. Part of the goal, also, is to decouple the form from the engine itself, so that you can have things like one search form (most likely a simple text field) and tie it to different engines for different sections.

Right now, the default SearchForm class that comes with the SS core has the search engine functionality tied into it. That makes it hard to extend.

Also, another goal of this module, if adopted into the core, would be to allow module developers to leverage some default, basic functionality and either extend it or tap into it. For example, I'm planning for the module to come with a basic text field and button search form class and a default site search engine that searches all SiteTrees. The, if someone builds a module that uses a DataObject that doesn't have its own controller but they want it to be searchable, they can include in the module's _config.php file something like SearchEngine::add_searchable_object('MyDataObject') and it will add it to the search engine without having to rewrite anything.

This framework could also influence developers to make more complex search engines as modules.

In the end, I think this will turn into something everyone will be able to use. The small problem I see with the current modules is that they are single purpose. Mine will allow people to easily write custom engines and build custom forms.

I know this is a lot of talk now, but that's how something like this starts. Just wait till you see what I come up with. ;-)

Sam Minnee

unread,
May 17, 2010, 10:50:05 PM5/17/10
to SilverStripe Core Development
How do we deal with these, and other features that I haven't heard of?

* spelling correction
* custom search fields

In particular, does the front-end need to inquire with the backend as
to whether it has spelling correction support?

Marcus Nyeholt

unread,
May 17, 2010, 11:24:07 PM5/17/10
to silverst...@googlegroups.com
In addition to spell checking (or auto suggest as some backends call it) 

* "More like this" searching
* Faceting
* Range based querying
* GIS based querying
* Relevancy scoring

I'd imagine you'd have to ask the backend what features it supports before trying to build the frontend 'advanced search' form. Additionally, some of this functionality isn't expressed directly in a search form or result list - eg facets could appear in other places around the site. Does that then become something that a theme designer relies on the search backend to provide details about?

Marcus

Matt Bower

unread,
May 17, 2010, 11:50:37 PM5/17/10
to silverst...@googlegroups.com
The framework will be largely abstract and mainly provide interaction hooks between the form and the engine. Creating one's own search engine will involve overloading class methods and extending the search form will involve binding DO columns to form fields that are added to a form via form object methods (for "advanced" search forms), or subclassing and overloading. There will likely be some methods that provide some functionality in the base classes, but a lot of it will definitely require overloading.

Matt

windandwaves

unread,
May 18, 2010, 6:01:28 AM5/18/10
to SilverStripe Core Development
Just to add a bit more chatter....

Searching is general about letting people find stuff on your website
that maybe hard to find through navigation. Here is my one cents
worth:

The key question is: "what are people looking for?". Any search setup
should include at least a way to review past search phrases and
possible also a way to create answer lists for common search phrases.

Also, in my opinion, it is not much use for an average website to
correct all spelling mistakes using a standard dictionary (unless your
run a very large site), but rather correct common mistakes (or
synonyms) relevant to the site being searched (for example, if you run
a restaurant you may want to correct "desert menu" to "dessert menu" -
something that a standard spelling correction would not pick up)).

To me, there are two types of search: the standard (a la Google) and
the advanced. So far, I have been talking about a simple search box.
An advanced search could include things like "date (e.g. last
updated), area of interest, type of document, language, etc... etc...
I guess this is more site specific. In practice, view people, apart
from academic / technical users take an interest in an advanced search
and even fewer would opt for the traditional boolean search (e.g.
AND / OR / AND NOT, etc...) It would be great if you can create a
custom advanced search for a website that makes use of the
standardised (modularised) simple search. I believe this is being
proposed here. Great.

Just a wee additional note I'd like to make is that the standard
Silverstripe Search includes the the MetaKeyword field in its standard
search that is part of Sapphire. What we tend to do is to put
keywords from other fields (e.g. image captions or whatever is
relevant) into the MetaKeyword field (onBeforeWrite seems the moment
to do this).

Hope this is of some (albeit limited) help.

Nicolaas

Ingo Schommer

unread,
May 24, 2010, 5:26:31 PM5/24/10
to SilverStripe Core Development
If you look at SearchForm vs. SphinxSearchForm for example, there's
currently not all that much duplicated view/controller code, so for a
simple 80% solution I don't see too much value in abstracting this any
further. That being said, both don't really include any form of
"advanced search" options and result presentation with all the
features mentioned above.

On a related note, it'd be awesome to have better fulltext search
support in the CMS "Search" panel (which filters the tree). Thats
handled quite differently through CMSSiteTreeFilter, which "marks"
pages including any parents which might not actually contain the
searched criteria. Phrase search currently works through MySQL LIKE
statements, so is fairly limited. Perhaps a two-stage search makes
sense, where we filter by custom criteria like "changes on draft"
first, and then do a second run on selected pages with Sphinx, Solr,
etc.

Marcus Nyeholt

unread,
May 24, 2010, 11:39:07 PM5/24/10
to silverst...@googlegroups.com
I think the point should be though, why does there need to be two separate search form implementations? Why can't there be one search form that describes a simple/advanced search interface, which on submission packages up the search parameters into a generic container (eg SearchContext), calls the configured search engine to perform a search and receive back a generic SearchResult container? 

Uncle Cheese

unread,
May 28, 2010, 4:32:01 PM5/28/10
to SilverStripe Core Development
I've had a lot of luck with a Google Search module I created. I figure
no one can do search better than they can. It's a descendant of the
GoogeleMaps class, and uses the sitemap.xml to create a search results
page with all the necessary metadata. The only downside is that you
have to pay for Google search to get rid of the branding. About $100 a
year, but it's well worth it in my opinion. I find extending the
search functionality very tiresome, and I'm happy to leave it in the
hands of a thirdparty, especially when the API is so generous with
presentation and creating custom meta data.



On May 24, 11:39 pm, Marcus Nyeholt <nyeh...@gmail.com> wrote:
> I think the point should be though, why does there need to be two separate
> search form implementations? Why can't there be one search form that
> describes a simple/advanced search interface, which on submission packages
> up the search parameters into a generic container (eg SearchContext), calls
> the configured search engine to perform a search and receive back a generic
> SearchResult container?
>
> > silverstripe-d...@googlegroups.com<silverstripe-dev%2Bunsubscrib e...@googlegroups.com>
> > .
> > > For more options, visit this group athttp://
> > groups.google.com/group/silverstripe-dev?hl=en.
>
> > --
> > You received this message because you are subscribed to the Google Groups
> > "SilverStripe Core Development" group.
> > To post to this group, send email to silverst...@googlegroups.com.
> > To unsubscribe from this group, send email to
> > silverstripe-d...@googlegroups.com<silverstripe-dev%2Bunsubscrib e...@googlegroups.com>
> > .
Reply all
Reply to author
Forward
0 new messages