January 14, 2011

Implement a Custom MultiListField using lucene search

I have recently experiment the Lucene search feature for sitecore. 
During my investigation I have create a custom multilist field but in place of using the classical datasource I use Lucene search to return the results. Here is the procedure to create it.

For this project I have use the shared source "Advanced Database Crawler" http://trac.sitecore.net/AdvancedDatabaseCrawler

The syntax I have used for the datasource is:

 IndexName=advanced&Language=en&TemplateFilter=&LocationFilter=&FullTextQuery=&FieldsFilter=Title:Sample,_templatename:Lucene Demo

Those parameters are the same as in the Demo 3 of the "Advanced Search Crawler". I have used the separator ',' as separator for the Fields filter and ':' for the second member. In my example, the field 'Title' need contain the word 'Sample' and the field '_templatename' need contain 'Lucene Demo'.

Add Advanced Database Crawler
Download http://trac.sitecore.net/AdvancedDatabaseCrawler and it to your solution.

Configure Sitecore
 In the core database, duplicate the item: /sitecore/system/Field types/List Types/Multilist rename it 'LuceneMultilist'. In the field 'Control' set the value to: MyPrefix:LuceneMultilist. You may choose your prefix, it only need to be the seem as in the next step.

Add a .config file
Add /App_Config/Include/LuceneMultilist.cs.config with this content:
<configuration xmlns:x="http://www.sitecore.net/xmlconfig/">
      <source mode="on" namespace="Your Namespace" assembly="Your Assembly Name" prefix="Your Prefix as in the field control" />

Implement your field
Add a new project to your solution and create a new class LuceneMultilist.cs.
The only think you need to implement is inheriting for the existing MultilistEx and override the method GetItems.

Here is the code
protected override Item[] GetItems(Item current)
    Assert.ArgumentNotNull(current, "current");

    //Split the source from the DataSource field
    NameValueCollection splitted = Sitecore.StringUtil.GetNameValues(Source, '=', '&');
    //Split the field FieldsFilter
    NameValueCollection splittedFields = Sitecore.StringUtil.GetNameValues(splitted["FieldsFilter"], ':', ',');

    //Create the refinements to filter on the Fields values
    var refinements = new SafeDictionary<string>();
    foreach (string key in splittedFields.Keys)
        refinements.Add(key, splittedFields[key]);                

    //Create the parameters as in the Demo 3 of Advanced Search Crawler
    var searchParam = new FieldValueSearchParam
        Refinements = refinements,
        LocationIds = splitted["LocationFilter"],
        TemplateIds = splitted["TemplateFilter"],
        FullTextQuery = splitted["FullTextQuery"],
        Occurance = QueryOccurance.Must,
        ShowAllVersions = false,
        Language = splitted["Language"]

    //Execute the search
    using (var searcher = new Searcher(splitted["IndexName"]))
        var items = searcher.GetItems(searchParam);
        return SearchHelper.GetItemListFromInformationCollection(items).ToArray();

Of course you need to add your own Lucene index or use an existing one. The tool : http://trac.sitecore.net/IndexViewer is usefull to see the content of the indexes.

It is done, Enjoy!

1 comment:

  1. Nice post man!
    I didn't know you had a blog. Thank you google :)