Kentico CMS 6.0 Developer's Guide

Defining custom index content

Defining custom index content

Previous topic Next topic Mail us feedback on this topic!  

Defining custom index content

Previous topic Next topic JavaScript is required for the print function Mail us feedback on this topic!  

Custom indexes are implemented by writing code, so the content indexed by them is not directly defined on the Index tab. All that needs to be done in the administration interface is specify the names of the assembly and class that contain the custom index code.

 

Each custom index must be defined by a class that implements the CMS.Siteprovider.ICustomSearchIndex interface.

 

To integrate this type of class into the application, you can add a new assembly (Class library) to your project and include it there. When using this approach, it is necessary to add the appropriate references to both the new assembly and the main CMS project. You can find a sample search index in the CustomSearchIndex project located in your Kentico CMS installation directory (typically C:\Program Files\KenticoCMS\<version>\CodeSamples\CustomSearchIndex).

 

Alternatively, you can define the custom index in App_Code without the need to compile an assembly, as described below.

 

Example:

 

The following example shows how you can create a custom index that searches the content of text files:

 

1. Open your web project, expand the App_Code folder (or Old_App_Code if you installed Kentico CMS as a web application), navigate to the Samples\Classes folder and edit the MyIndex.cs file. This file already contains a sample class that follows the basic structure required for a custom search index:

 

[C#]

 

using CMS.EventLog;
using CMS.SiteProvider;
using CMS.SettingsProvider;
using CMS.GlobalHelper;
using CMS.IO;
 
using Lucene.Net.Index;
using Lucene.Net.Documents;
 
namespace Custom
{
    /// <summary>
    /// Sample custom search index class.
    /// In this example, all text files from a specified directory are indexed.
    /// </summary>
    public class MyIndex : ICustomSearchIndex
    {
        ...
    }
}

 

Add any of the references listed above that are not already included in the file's code.

 

2. The most important part of an index's code that must always be included is its Rebuild method. It is used to fill the index with data, which determines what kind of searches will be possible. The method is called when the index is created and on each subsequent rebuild.

 

Place the following code into the method:

 

[C#]

 

/// <summary>
/// Implementation of the rebuild method.
/// </summary>
/// <param name="srchInfo">Search index info</param>
public void Rebuild(SearchIndexInfo srchInfo)
{
    // Checks whether the index info object is defined.
    if (srchInfo != null)
    {
        // Gets an index writer object for the current index.
        IndexWriter iw = srchInfo.GetWriter(true);
 
        // Checks the whether writer is defined.
        if (iw != null)
        {
            try
            {

          // Gets an info object of the index settings.
          SearchIndexSettingsInfo sisi = srchInfo.IndexSettings.Items[SearchHelper.CUSTOM_INDEX_DATA];

 
            // Gets the search path from the Index data field.
            string path = Convert.ToString(sisi.GetValue("CustomData"));
 
            // Checks whether the path is defined.
            if (!String.IsNullOrEmpty(path))
            {
                // Gets all text files from the specified directory.
                string[] files = Directory.GetFiles(path, "*.txt");
 
                // Loops through all files.
                foreach (string file in files)
                {
                    // Gets the current file info.
                    FileInfo fi = FileInfo.New(file);
 
                    // Gets the text content of the current file.
                    string text = fi.OpenText().ReadToEnd();
 
                    // Checks that the file is not empty.
                    if (!String.IsNullOrEmpty(text))
                    {
                    // Converts the text to lower case.
                    text = text.ToLower();
                    // Removes diacritics.
                    text = TextHelper.RemoveDiacritics(text);

 
                  // Creates a new Lucene.Net search document for the current text file.
                  Document doc = SearchHelper.CreateDocument(SearchHelper.CUSTOM_SEARCH_INDEX, Guid.NewGuid().ToString(), SearchHelper.INVARIANT_FIELD_VALUE, fi.CreationTime, SearchHelper.INVARIANT_FIELD_VALUE);
 
                  // Adds a content field. This field is processed when the search looks for matching results.
                  SearchHelper.AddField(doc, SearchHelper.CONTENT_FIELD, text, false, true);
 
                  // Adds a title field. The value of this field is used for the search results title.
                  SearchHelper.AddField(doc, SearchHelper.CUSTOM_TITLE, fi.Name, true, false);
 
                  // Adds a content field. The value of this field is used for the search result excerpt.
                  SearchHelper.AddField(doc, SearchHelper.CUSTOM_CONTENT, TextHelper.LimitLength(text, 200), true, false);
 
                  // Adds a date field. The value of this field is used for the date in the search results.
                  SearchHelper.AddField(doc, SearchHelper.CUSTOM_DATE, fi.CreationTime, true, false);
 
                  // Adds a url field. The value of this field is used for link urls in the search results.
                  SearchHelper.AddField(doc, SearchHelper.CUSTOM_URL, file, true, false);
 
                  // Adds a title field. The value of this field is used for the images in the search results.
                  //SearchHelper.AddField(doc, SearchHelper.CUSTOM_IMAGEURL, "textfile.jpg", true, false);

 
                    // Adds the document to the index.
                    iw.AddDocument(doc);
                    }
                }
 
                // Optimizes the index.
                iw.Optimize();
            }
            }
 
            // Logs any potential exceptions.
            catch (Exception ex)
            {
                EventLogProvider.LogException("CustomIndex""Rebuild", ex);
            }
            // Always close the index writer.
            finally
            {
                iw.Close();
            }
        }
    }
}

 

The exact code used to build a search index depends on its specific purpose, but the sample above shows the general principles that apply to all indexes. You will first need to create an IndexWriter object, then define appropriate search Documents (Lucene.Net.Documents.Document objects) and their fields. Once the documents are added to the index writer, you can optimize and close it.

 

The SearchIndexInfo parameter of the method can be used to access the data fields of the corresponding search index object. As you can see in the code above, the content of the Index data field is loaded and used to define the path to the searched text files. When writing your own custom indexes, you can use this field as a string parameter for any required purpose. This way, you can easily modify the behaviour of the index directly from the administration interface without having to edit its code.

 

Save the changes made to the MyIndex.cs file.

 

3. Next, it is necessary to ensure that the MyIndex class is loaded when the corresponding search index is created or rebuilt. Expand the Samples\Modules folder and open the SampleClassLoaderModule.cs file, which demonstrates how this can be done. You do not have to make any modifications for the purposes of this example, since the sample class loader handles the Custom.MyIndex class by default.

 

An object of the appropriate class is assigned by the ClassHelper_OnGetCustomClass event handler:

 

[C#]

 

/// <summary>
/// Gets a custom class object based on the given parameters.
/// </summary>
private void ClassHelper_OnGetCustomClass(object sender, ClassEventArgs e)
{
    if (e.Object == null)
    {
        // Passes on an object of the appropriate custom class.
        switch (e.ClassName)
        {
            ...

 
          // Gets an object of the MyIndex class implementing the ICustomSearchIndex interface.

            case "Custom.MyIndex":
                e.Object = new Custom.MyIndex();
                break;
 
            ...
 
        }
    }
}

 

In the case of search indexes, the value of the ClassName property of the handler's ClassEventArgs parameter will match the Class name specified for the given index on its Index tab (Custom.MyTask in this example). When this value is identified, an instance of the appropriate class is created and passed on.

 

4. Build the project if you installed it as a web application.

 

5. Now you need to create a folder for the text files that this index will search. This example will use C:\SearchExample. Either create or copy some existing text file into this folder.

 

6. Open Kentico CMS, go to Site Manager -> Administration -> Smart Search and click NewIndex New Index. Fill in the following properties:

 

Display name: Text file index

Code name: TextFileIndex

Index type: Custom Index

 

Click OK.

 

7. Now switch to the Index tab and enter the following:

 

Assembly name: App_Code

Class name: Custom.MyIndex

Index data: C:\SearchExample\

 

devguide_clip1144

 

These are the names of the assembly and class where the custom index is implemented. Click OK.

 

8. Finally, go to the General tab and RebuildIndex Rebuild the index. The index should now be fully functional. If you wish, you can test the index by switching to the Search preview tab and trying to search for any words from the text files you created in the SearchExample folder.