+1-888-365-2779
Try Now
More in this section

Forums / Developing with Sitefinity / How to search for mutliple search indexes?

How to search for mutliple search indexes?

12 posts, 0 answered
  1. MJia
    MJia avatar
    44 posts
    Registered:
    09 Jun 2009
    11 Dec 2009
    Link to this post
    Hi, we need to implement a bit complex site search in SiteFinity.
    I have created different search indexes for each section of the site, such as 'about us', 'publications', 'rules', etc.
    I want to display a list of checkboxes in search box, allow client to select one for more sections they want to search. 
    How can I do that?
    I learned the sample of selecting one section and then changing the SearchBox1.IndexCatalogue.  But how to apply multiple index catalogues to one search?

    Please advice,
    Thanks.
  2. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    25 Nov 2016
    13 Dec 2009
    Link to this post
    Hello MJia,

    SearchResult and Search box are not develop to work with multiple separate indexes and this is the idea of combined index. However there are two options.

    1. Modify SearchBox control and pass different value in the url bar as a QueryString so that the SearchResult will display different results.

    Sample code:

    Modify SearchBox template

    <%@ Control Language="C#" %>
    <%@ Register Assembly="Telerik.Cms.Web.UI" Namespace="Telerik.Cms.Web.UI" TagPrefix="sfWeb" %>
     
    <sfWeb:CssFileLink ID="CssFileLink1" FileName="~/Sitefinity/ControlTemplates/Search/searchCommonLayout.css" Media="screen" runat="server" />
     
    <script type="text/C#" runat="server">
     
        public void Page_Load(object sender, EventArgs e)
        {
         
            searchButton1.Click += new EventHandler(searchButton1_Click);
          
        }
     
        void searchButton1_Click(object sender, EventArgs e)
        {
            if (CheckBox1.Checked)
            {
                CheckBox2.Checked = false;
                Response.Redirect(Request.RawUrl + "?IndexCatalogue=" + CheckBox1.Text + "&SearchQuery=" + queryText.Text);
            }
            if (CheckBox2.Checked)
            {
                CheckBox1.Checked = false;
                Response.Redirect(Request.RawUrl + "?IndexCatalogue=" + CheckBox2.Text + "&SearchQuery=" + queryText.Text);
            }
        }
    </script>
     
    <fieldset class="sf_searchBox">
        <asp:Label runat="server" AssociatedControlID="queryText" Text="Search" />
        <asp:TextBox ID="queryText" runat="server" CssClass="sf_searchText"></asp:TextBox>
        <input style="display:none;" type="button" id="searchButton" runat="server"  class="sf_searchSubmit" value="Search" alt="Search"/>
       <asp:Button ID="searchButton1" runat="server" Text="CustomSearchButton" />
    </fieldset>
     
    <asp:CheckBox runat="server" ID="CheckBox1" Text="SearchInNews" AutoPostBack="true" />
    <asp:CheckBox runat="server" ID="CheckBox2" Text="SearchInBlogs" AutoPostBack="true" />

    2. Option two is creating a custom search result control which  by default will load all results, but you will decide which of them to hide.

    Sample code - you have to inherit from SearchResults class and implement custom logic inside CreateChildControls method.

    Here you will set the new data source of SearchResult control depending on the items that you want to see displayed.

    protected override void CreateChildControls()
           {
                
               this.layoutCnt.ResultsList.ItemDataBound += new RepeaterItemEventHandler(ResultsList_ItemDataBound);
               this.layoutCnt.ResultsList.DataBind();
     
               this.Controls.Clear();
     
               this.layoutCnt = new Container(this);
               this.LayoutTemplate.InstantiateIn(layoutCnt);
     
               if (!string.IsNullOrEmpty(Query))
               {
                   string vPath = PathUtil.GetIndexPhysicalPath(this.IndexCatalogue);
                   string nPath = PathUtil.GetIndexPhysicalPath(NewCatalogName);
                   if (Directory.Exists(vPath) && Directory.Exists(nPath))
                   {
                       // check if query string is supplied to select the current page
                       if (!string.IsNullOrEmpty(HttpContext.Current.Request.QueryString[PageKey]))
                       {
                           this.CurrentPage = Convert.ToInt32(
                               HttpContext.Current.Request.QueryString[PageKey]);
                       }
     
                       string searchQuery = Query;
                       string message = string.Empty;
     
                       bool isValid = this.EscapeSpecialChars ? this.EscapeSpecialChars : ValidateQuery(ref searchQuery, out message);
     
                       if (isValid)
                       {
                           int totalItems;
                           int totalItems2;
                           int startIndex = (this.CurrentPage - 1) * this.PostsPerPage;
     
                           try
                           {
                               IList<ResultItem> dataSource = SearchManager.Search(
                                   searchQuery,
                                   this.IndexCatalogue,
                                   startIndex,
                                   this.PostsPerPage,
                                   this.WordsMode,
                                   this.EscapeSpecialChars,
                                   out totalItems);
     
                               IList<ResultItem> newDS = SearchManager.Search(
                                      searchQuery,
                                      NewCatalogName,
                                      startIndex,
                                      this.PostsPerPage,
                                      this.WordsMode,
                                      this.EscapeSpecialChars,
                                      out totalItems2);
     
                               IList<ResultItem> newList = new List<ResultItem>();
                               foreach (ResultItem item in dataSource)
                               {
                                   newList.Add(item);
                               }
                               foreach (ResultItem newDSitem in newDS)
                               {
                                   newList.Add(newDSitem);
                               }
     
     
                               totalItems = totalItems + totalItems2;
     
                               int numberOfPages = (this.PostsPerPage == 0) ? 1 : (int)Math.Ceiling((double)totalItems / (double)this.PostsPerPage);
     
                               if (numberOfPages == 0 && totalItems > 0)
                                   numberOfPages = 1;
     
                               string qeryTest = this.Query.Trim('\"');
                               ((Control)this.layoutCnt.ResultsStats).EnableViewState = false;
                               this.layoutCnt.ResultsStats.Text = string.Format(this.layoutCnt.ResultsStats.Text, totalItems, qeryTest);
     
                               if (this.AllowPaging)
                               {
                                   this.layoutCnt.Pager1.SelectedPageChanged += new EventHandler<EventArgs>(Pager_SelectedPageChanged);
                                   this.layoutCnt.Pager1.PageCount = numberOfPages;
                                   this.layoutCnt.Pager1.SelectedPage = this.CurrentPage;
                               }
                               this.layoutCnt.ResultsList.DataSource = newList;
     
                           }
                           catch (Telerik.Lucene.Net.QueryParsers.ParseException ex)
                           {
                               this.layoutCnt.ResultsStats.Text = "strange chars";
                               Log.Exception(ex);
                           }
                       }
                       else
                       {
                           this.layoutCnt.ResultsStats.Text = message;
                       }
                   }
                   else
                   {
                       this.layoutCnt.ResultsStats.Text = String.Format("InvalidIndex", this.IndexCatalogue);
                   }
               }
               else
               {
                   this.layoutCnt.ResultsStats.Text = String.Empty;
               }
     
               this.layoutCnt.ResultsList.ItemDataBound += new RepeaterItemEventHandler(ResultsList_ItemDataBound);
               this.layoutCnt.ResultsList.SkinID = this.SkinID;
     
               Controls.Add(this.layoutCnt);
               this.layoutCnt.ResultsList.DataBind();
     
           }


    Greetings,
    Ivan Dimitrov
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
  3. MJia
    MJia avatar
    44 posts
    Registered:
    09 Jun 2009
    14 Dec 2009
    Link to this post
    Thanks Ivan,
    I think option 2 is more appropriate in our case. 
    Can you provide more details about how to create a custom search result control?  I like to have a step-by-step tutor. Thanks.

    There's one more question to make it work:  In CreateChildControls method how can I get the client's choices of catalogs that they want to search?
    I guess we need to customize the searchbox control as well to add in bunches of check boxes to allow clients to select from different catalogs.  But how to pass user's selections to searchresults control?

    Please advice.
    Thanks.
  4. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    25 Nov 2016
    14 Dec 2009
    Link to this post
    Hello MJia,

    Below are the steps that you have to follow to create a custom control that inherits from SearchResults.

    1. Create a class that inherits from SearchBox

    2. Create a search box toolbox item that inherits from Telerik.Web.ToolboxItem

    3. Override CreateChildControls as shown above.

    can I get the client's choices of catalogs that they want to search?\

    You need to create a custom template for the control - for instance chechbox list and populate the list using the following code

    CheckBoxList.DataSource = Telerik.Search.Engine.IndexingManager.IndexingServices;
    CheckBoxList.DataTextField = "key";
    CheckBoxList.ServicesList.DataBind();

    You can create a container or just control reference using GetControl<T> to the checkbox list to handle the customer's choice. Then you will bind the SearchResults repeater the the appropriate list.

    Regards,
    Ivan Dimitrov
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
  5. MJia
    MJia avatar
    44 posts
    Registered:
    09 Jun 2009
    14 Dec 2009
    Link to this post
    Hi, Ivan,
    Thanks for the quick reply.
    I donot understand this step: 2. Create a search box toolbox item that inherits from Telerik.Web.ToolboxItem
    How do I create that item? What does it do with the custom search result class?

    And what will happen after I created the custom search result class? Should I register it to the system so it can be used by other pages?

    Sorry I am really new in SiteFinity development so I like to get more detail instructions.
    It would be best if you can provide a sample for this.

    Thanks a lot.

  6. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    25 Nov 2016
    14 Dec 2009
    Link to this post
    Hello MJia,

     Below is a sample code

    public class SearchResultsCustomToolboxItem : Telerik.Web.ToolboxItem
    {
            #region Construction
        public SearchResultsCustomToolboxItem ()
            : base(typeof(SitefinitySamples.SearchResultsCustom))
            {
                base.DisplayName = "SearchResults";
            base.Description = "SearchResults";
     
            }
            #endregion
     
    }
     
    namespace SitefinitySamples
    {
     
        [System.ComponentModel.ToolboxItem(typeof(SearchResultsCustomToolboxItem ))]
        public class SearchResultsCustom: SearchResult
        {
        }
    }

    Actually you already have almost the whole control written.


    Greetings,
    Ivan Dimitrov
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
  7. MJia
    MJia avatar
    44 posts
    Registered:
    09 Jun 2009
    14 Dec 2009
    Link to this post
    Thanks Ivan.
    Now I've created the custom search result class and custome search result toolbox item class.
    And what will happen after then? How should I register it to the system so it can be used by other pages?

    Edit:
    After checking other posted forum articles, I managed to register the class as a user control in web.config.  And I tested it successfully in a test page.
    Now I met another problem.  I plan to do one search to get all results first, then filter them based on user's selections.
    The code looks like the following:
                              
                                IList<ResultItem> newnewList = new List<ResultItem>(); 
                                foreach (ResultItem item in dataSource) 
                                { 
                                    //For the 'item' that falls in what user selects 
                                    newList.Add(item); 
                                } 
     

    I've created a custom search index to index contents from a database table, the customized indexer info class includes new fields like 'typeID'.
    I found the ResultItem can only return basic content information like 'title', 'snippet', 'url', how can I get more information of that piece of item such as the 'typeID' ?  (So that I can easily filter items based on user's choices)

    Please advice.
    Thanks.

    Thanks.
  8. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    25 Nov 2016
    15 Dec 2009
    Link to this post
    Hello MJia,

     You can use only the ResutlItem properties - Title, snippet, Url, Score. You can add Item ID as well.

    Sincerely yours,
    Ivan Dimitrov
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
  9. MJia
    MJia avatar
    44 posts
    Registered:
    09 Jun 2009
    15 Dec 2009
    Link to this post
    Oh okay.
    Can you let me know how to add 'item id' and retrieve it?
    Also can I retrieve the metadata in any means from resultitem?

    Thanks.

  10. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    25 Nov 2016
    15 Dec 2009
    Link to this post
    Hello MJia,

    You can take a look at the following post that shows how to extract the item ID Search to Provide Article ID . Once you have the ID you can use CmsManager ( for pages) or ContentManager ( for content item objects).


    Regards,
    Ivan Dimitrov
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
  11. MJia
    MJia avatar
    44 posts
    Registered:
    09 Jun 2009
    16 Dec 2009
    Link to this post
    Hi, Ivan,
    I am almost there. Now the only issue left is to pass user's choices into my search result control.
    You said:
    You need to create a custom template for the control - for instance chechbox list and populate the list using the following code ...
    I guess 'the control' here refers to the search box contorl, correct?
    I already created a custom search box template in /Sitefinity/ControlTemplates/Search/ folder and added some checkboxes in there.

    You said:
    You can create a container or just control reference using GetControl<T> to the checkbox list to handle the customer's choice. Then you will bind the SearchResults repeater the the appropriate list.
    Can you explain more on this? I created a custom search result template for our own layout, I also created a custom search result class in app_code that inherits SearchResult and override the CreateChildControls method.
    I need to deal with user's choices in CreateChildControls method.  How exactly can I do that? Can you write some sample codes for me?

    Thanks a lot.
  12. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    25 Nov 2016
    17 Dec 2009
    Link to this post
    Hi MJia,

    1. Add controls - say CheckBox in the template of Search Results control

    2. Override CreateChildControls and find the control from the template

    3. Subscribe for CheckedChanged and check whether the given Checkbox is checked or not.

    protected override void CreateChildControls()
        {
            //base.CreateChildControls();
             
            CheckBox checkbox = this.layoutCnt.GetControl<CheckBox>("cb1", true)
                if(checkbox !=null)
                {
                    checkbox.CheckedChanged +=new EventHandler(checkbox_CheckedChanged);
                }
     
        }
     
        void checkbox_CheckedChanged(object sender, EventArgs e)
        {
            
        }

    Kind regards,
    Ivan Dimitrov
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
Register for webinar
12 posts, 0 answered