+1-888-365-2779
Try Now
More in this section
Categories
Bloggers
Blogs RSS feed

Search Index with custom fields in sitefinity 4

by Teodor Georgiev

This is going to be a HOW to configure  the search indexes in sitefinity to index and search on more than the default fields. 

1. You have to add the fields in sitefinity search index. The search system is based on the publishing system so the way to add additional fields is  like this :   


var ContentSearchPipesSettigns = PublishingSystemFactory.GetTemplatePipes("SearchItemTemplate").Where(ps => ps.PipeName == ContentInboundPipe.PipeName && ps.IsInbound).FirstOrDefault();
 
          if (!ContentSearchPipesSettigns.Mappings.Mappings.Any(mp => mp.DestinationPropertyName == "TestField"))
          {
              var mapping = PublishingSystemFactory.CreateMapping("TestField", TransparentTranslator.TranslatorName, false, "TestField");
 
              ContentSearchPipesSettigns.Mappings.Mappings.Add(mapping);
 
              PublishingSystemFactory.RegisterTemplatePipe("SearchItemTemplate", ContentSearchPipesSettigns, ps => ps.PipeName == ContentInboundPipe.PipeName && ps.IsInbound);
          }
 
 
          var searchPipesSettigns = PublishingSystemFactory.GetTemplatePipes("SearchItemTemplate").Where(ps => ps.PipeName == SearchIndexOutboundPipe.PipeName && !ps.IsInbound).FirstOrDefault();
 
          if (!searchPipesSettigns.Mappings.Mappings.Any(mp => mp.DestinationPropertyName == "TestField"))
          {
              var mappingTest = PublishingSystemFactory.CreateMapping("TestField", TransparentTranslator.TranslatorName, false, "TestField");
 
              searchPipesSettigns.Mappings.Mappings.Add(mappingTest);
 
              PublishingSystemFactory.RegisterTemplatePipe("SearchItemTemplate", searchPipesSettigns, ps => ps.PipeName == SearchIndexOutboundPipe.PipeName && !ps.IsInbound);
          }

First we add a  field named "TestField" in the inbound pipe and second  part add the field into the search index pipe.  This is changing the default search index template so all your search indexes should be recreated (deleted and created again) to apply this settings. 

2. Now you have the field in the search index. So now you have to replace the provider to be able to have control over the fields that are part of the search queries : 


var section = Config.Get<SearchConfig>();
           foreach (var provider in section.Providers.Values)
           {
               if (provider.Name == "LuceneSearchProvider")
               {
                   if (provider.ProviderType == typeof(LuceneSearchProvider))
                   {
                       provider.ProviderType = typeof(LucenseCustomSearchProvider);
                       ConfigManager.GetManager().SaveSection(section);
                       break;
                   }
               }
           }

3. You have to implement this Custom lucene  search provider  like this  : 


public class LucenseCustomSearchProvider : LuceneSearchProvider
    {
        public override IResultSet Find(string catalogueName, string query, int skip, int take, params string[] orderBy)
        {
            return new LuceneCustomResultSet(this, catalogueName, query, skip, take, orderBy);
        }
 
        public override IResultSet Find(string catalogueName, string query, params string[] orderBy)
        {
            return new LuceneCustomResultSet(this, catalogueName, query, orderBy);
        }
    }

4. And the last thing is to implement the custom search result set  : 

public class LuceneCustomResultSet : LuceneResultSet
{
 
     public LuceneCustomResultSet(LuceneSearchProvider provider, string catalogueName, string query, params string[] orderBy)
        : this(provider, catalogueName, query, 0, 0, orderBy)
    {
         
    }
 
     string catalogueName = String.Empty;
     public LuceneCustomResultSet(LuceneSearchProvider provider, string catalogueName, string query, int skip, int take, params string[] orderBy)
         : base(provider, catalogueName, query, 0, 0, orderBy)
     {
         this.catalogueName = catalogueName;
         this.query = query;
     }
 
    protected override void ExecuteQuery(bool tryToFix = true)
    {
        try
        {
            var path = ((LuceneSearchProvider)SearchManager.GetManager("").Provider).GetCataloguePath(catalogueName);
            if (System.IO.Directory.Exists(path))
            {
                var defautlOperator = QueryParser.AND_OPERATOR;
                var analyzer = this.GetAnalyzer();
 
                var parser = new MultiFieldQueryParser(new string[] { "Title", "Content", "TestField" }, analyzer);
                parser.SetDefaultOperator(defautlOperator);
 
                //query = QueryParser.Escape(query);
 
                if (searcher != null)
                    searcher.Close();
 
                searcher = new IndexSearcher(path);
                Query queryObj = searcher.Rewrite(parser.Parse(query));
                Query = queryObj;
 
                //Search only for current language
                if (AppSettings.CurrentSettings.Multilingual == true)
                {
                    TermQuery languageQuery = new TermQuery(new Term("Language", CultureInfo.CurrentUICulture.Name));
                    TermQuery languageNullQuery = new TermQuery(new Term("Language", SearchProvider.FieldNullValue));
 
                    BooleanQuery filterQuery = new BooleanQuery();
                    filterQuery.Add(languageQuery, BooleanClause.Occur.SHOULD);
                    filterQuery.Add(languageNullQuery, BooleanClause.Occur.SHOULD);
 
                    QueryFilter languageFilter = new QueryFilter(filterQuery);
 
                    this.hits = searcher.Search(queryObj, languageFilter);
                }
                else
                {
                    this.hits = searcher.Search(queryObj);
                }
 
                for (var iter = 0; iter < this.HitCount; iter++)
                {
                    var doc = this.hits.Doc(iter);
                }
            }
        }
        catch (Exception ex)
        {
            if (tryToFix && ex is ParseException)
            {
                this.query = this.TryFixQuery(this.query);
                this.ExecuteQuery(false);
            }
            else
            {
                this.error = ex;
                this.hits = null;
            }
        }
    }
 
    private Exception error;
    private string query;
    private IndexSearcher searcher;
    public void Dispose()
    {
        if (this.searcher != null)
        {
            this.searcher.Close();
            this.searcher = null;
        }
    }
}



Note that steps  3 and 4  will be changed at some point to be able to achieve this in less steps and less code. 


6 comments

Leave a comment
  1. Miles Jan 25, 2012
    Where are you putting this code you're creating? And how are you registering it with the system?
  2. Ivan Pelovski Feb 21, 2012
    Hi Miles. The first code sample should be placed in a "Bootstrapper.Initialized" event handler or in the initialization method of a custom module. The second code sample should be run only once and can be placed in a simple page. But since it can be run safely every time the code can be put together with the one from the first sample. The third code sample is a class and can be put in a code file somewhere in your projects. The same is valid and for the fourth code sample but this time the custom control should be registered in the Toolbox of Sitefinity in order to be used.
  3. Jason May 17, 2012
    Hello Teodor, Ivan
    I was looking for such type of feature. Can you please elaborate the steps in more details like where we have to add the above code snippet and other changes also.  So that I can use that as a reference.

    Thanks in advance
     

  4. Jason May 17, 2012
    Hello Teodor, Ivan
    I was looking for such type of feature. Can you please elaborate the steps in more details like where we have to add the above code snippet and other changes also.  So that I can use that as a reference.

    Thanks in advance
     

  5. Mateen Aug 28, 2014

    Hi Teodor, Ivan

    I want to add image in search result. I gone through your code and implemented same at my end but somehow it is not working.

    It will be great if you can please explain it in bit detail.

    Thanks

  6. Mateen Aug 28, 2014

    Hi,

    I got the solution from below mentioned article, don't know why but I not able to paste hyperlink here.

    Customizing Sitefinity SearchResults - displaying Product thumbnails and other Content type-specific data

    Thank you.

    Leave a comment