We had a scenario recently where we had 2 indexes set up in Kentico to search different folders within a site. Everything worked as expected until we threw attachment searching into the mix. Filters you set up in the Indexes property are ignored resulting in all pages with an attachment being returned.

We had a scenario recently where we had 2 indexes set up in Kentico to search different folders within a site. Everything worked as expected until we threw attachment searching into the mix.

The Setup

CMSDesk > Content
I have 3 pages configured for this example:

  1. News
  2. Resources
  3. Search
  • News has many CMS.News items below it. One of those news items has the text FINDME
  • Resources has the text FINDME in it and an attachment test.txt with the word “test” in it.
  • Search has a SearchResults Webpart on it configured as follows:

<ctrl:searchresults id="cSearchResults" indexes="MySite.News" runat="server" searchinattachments="true">

CMSSiteManager > Administration > Smart search
Index “MySite.News” is specified as:

  • Path: /News/%
  • Documents: CMS.News
  • Index Type: Allowed

Reproducing The Error:

With the above configuration if I search for “FINDME” I get 2 pages in the results (News + Resources). This is wrong on a few levels.
The attachment does not contain the text FINDME
The Index states that we only want to search CMS.News doc types
The Index states that we only want to search in the path /News/%

The Problem

When you set SearchInAttachments=”True” in the SearchResults user control, it ignores the filters you set in the Indexes property and will return all pages with an attachment that matches your search.

Kentico’s response to this was to use the Path property or use the AttachmentsWhere property. Path was not useful to us because some of our searches required multiple path’s to be searched. So what I have done is create this function which will look at what Indexes are selected and generate a AttachmentsWhere clause for us instead.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
 
using CMS.SiteProvider;
using CMS.SettingsProvider;
 
namespace Revium
{
    public static class SmartSearch
    {
        /// <summary>
        /// Generates a WHERE clause for the AttachmentsWhere property of a
        /// SearchResults user control based on the indexes assigend to the
        /// Indexes property ~/CMSWebParts/SmartSearch/SearchResults.ascx
        /// </summary>
        /// <param name="indexes">Smart search index Code Names separated by semi colons: index1;index2;index3
        /// <returns>
        /// Example WHERE clauses generated
        ///     excluded1
        ///     excluded1 AND excluded2
        ///     ( allowed1 )
        ///     ( allowed1 OR allowed2 )
        ///     excluded1 AND ( allowed1 )
        ///     excluded1 AND excluded2 AND excluded_n AND ( allowed1 OR allowed2 OR allowed_n)
        ///
        /// allowed samples:
        ///     NodeAliasPath LIKE '/News/%'
        ///     NodeAliasPath LIKE '/News/%' AND ClassName = 'CMS.News'
        ///
        /// excluded samples:
        ///     NodeAliasPath NOT LIKE '/News/%'
        ///     NodeAliasPath NOT LIKE '/News/%' AND ClassName = 'CMS.News'
        /// </returns>
        public static string GetSearchAttachmentsWhere(string indexes)
        {
            string attachmentsWhere = string.Empty;
            string attachmentsPathInc = string.Empty;
            string attachmentsPathExc = string.Empty;
 
            string[] indexArray = indexes.Split(';');
 
            //For each index that this SearchResults control is using
            foreach (string index in indexArray)
            {
                if (string.IsNullOrEmpty(index))
                    continue;
 
                //Get the index data
                SearchIndexInfo sii = SearchIndexInfoProvider.GetSearchIndexInfo(index);
 
                //For each index setting in this index construct a filter
                //i.e. NodeAliasPath like '/News' AND ClassName = 'CMS.News'
                foreach (Guid key in sii.IndexSettings.Items.Keys)
                {
                    SearchIndexSettingsInfo sisi = sii.IndexSettings.Items[key];
 
                    if (sisi.Type == "allowed")
                    {
                        //i.e. NodeAliasPath like '/News/%'
                        string indexCondition = string.Format(" NodeAliasPath LIKE '{0}' ", sisi.Path);
 
                        //i.e. NodeAliasPath like '/News/%' AND ClassName = 'CMS.News'
                        if (!string.IsNullOrEmpty(sisi.ClassNames))
                            indexCondition += string.Format(" AND ClassName = '{0}' ", sisi.ClassNames);
 
                        //i.e. (NodeAliasPath like '/News/%' AND ClassName = 'CMS.News')
                        indexCondition = string.Format(" ({0}) ", indexCondition);
 
                        //i.e. (NodeAliasPath like '/News/%' AND ClassName = 'CMS.News') OR (NodeAliasPath like '/Blog/%' AND ClassName = 'CMS.Blog')
                        if (!string.IsNullOrEmpty(attachmentsPathInc))
                            attachmentsPathInc += " OR ";
 
                        attachmentsPathInc += indexCondition;
                    }
                    else
                    {
                        //i.e. NodeAliasPath like '/News/%'
                        string indexCondition = string.Format(" NodeAliasPath NOT LIKE '{0}' ", sisi.Path);
 
                        //i.e. NodeAliasPath like '/News/%' AND ClassName = 'CMS.News'
                        if (!string.IsNullOrEmpty(sisi.ClassNames))
                            indexCondition += string.Format(" AND ClassName = '{0}' ", sisi.ClassNames);
 
                        //i.e. (NodeAliasPath like '/News/%' AND ClassName = 'CMS.News')
                        indexCondition = string.Format(" ({0}) ", indexCondition);
 
                        //i.e. (NodeAliasPath like '/News/%' AND ClassName = 'CMS.News') AND (NodeAliasPath like '/Blog/%' AND ClassName = 'CMS.Blog')
                        if (!string.IsNullOrEmpty(attachmentsPathExc))
                            attachmentsPathExc += " AND ";
 
                        attachmentsPathExc += indexCondition;
                    }
                }
            }
 
            //Add all the excluded content to the WHERE Statement
            if (!string.IsNullOrEmpty(attachmentsPathExc))
                attachmentsWhere += attachmentsPathExc;
 
            //Add all the included content to the WHERE Statement
            if (!string.IsNullOrEmpty(attachmentsPathInc))
            {
                if (!string.IsNullOrEmpty(attachmentsWhere))
                    attachmentsWhere += " AND ";
 
                attachmentsWhere += string.Format(" ({0}) ", attachmentsPathInc);
            }
 
            return attachmentsWhere;
        }
    }
}

 

You may also like

Kentico Mobile Development Competency

Revium is both proud and excited to be awarded with a Kentico Mobile Development Competency. This is recognition of the high quality mobile development work we have done for our clients.

Keep Reading

Kentico 6.0 Custom BizForm Validation

We have been working with Kentico and their BizForms module for a while now to implement “simple” forms to capture data. But like any work you do that uses the word simple, it quickly becomes a complex form with conditional validation. Revium uses custom form controls to extend Kentico BizForms.

Keep Reading

Newsletter sign up

Every couple of months we send out an update on what's been happening around our office and the web. Sign up and see what you think. And of course, we never spam.