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

Forums / Developing with Sitefinity / Sitefinity 6 Search Indexes

Sitefinity 6 Search Indexes

10 posts, 0 answered
  1. Nicole
    Nicole avatar
    5 posts
    Registered:
    05 Sep 2013
    12 Dec 2013
    Link to this post
    Hello all, I just had a question about the search indexes in Sitefinity 6. Is there a way to limit the pages that get searched? For example, let's say I have a Home, About and Products pages set as parent nodes. Is there a way to limit a search to just the Products pages and it's child nodes? I know this could be done in Sitefinity 3.7 and would appreciate help getting the same results in 6.1!

    Thank you for your help!
  2. Melyssa
    Melyssa avatar
    8 posts
    Registered:
    21 Jan 2013
    12 Dec 2013
    Link to this post
    Hi - I also have this same requirement. I have a site that is organized by departments in a hierarchical fashion and need to be able to allow users to select to which department they would like to limit their search. Essentially, custom scopes defined by groups of pages. The only thing I have found mentions having to create custom pipes for something like this. Is this the only way? And if so, can you please provide sample code on doing this? Thanks -
  3. Stephen2
    Stephen2 avatar
    94 posts
    Registered:
    05 Feb 2012
    14 Dec 2013
    Link to this post
    Yeah.... Not really.... The way I override stuff like this is to override the SearchResults widget and put custom logic in there.

    Here is an example that I have stripped back for this example, it may have a bug or two as I'm stripping things away, but it should make sense.  FYI it's just taken from Reflector and edited:

    public class CustomSearchResults : SearchResults {
        //Stolen from JustDecompile, then changed as necessary
        //This method eliminates DUD (permission based) links to pages & documents
        protected override void InitializeControls(Telerik.Sitefinity.Web.UI.GenericContainer container) {
            //Do default things
            base.InitializeControls(container);
     
            bool escapeSpecialChars;
            Label resultsStats = this.ResultsStats;
     
            if (string.IsNullOrEmpty(this.Query)) {
                this.ResultsStats.Text = string.Empty;
                return;
            } else {
                string query = this.Query;
                string empty = string.Empty;
                if (this.EscapeSpecialChars) {
                    escapeSpecialChars = this.EscapeSpecialChars;
                } else {
                    escapeSpecialChars = this.ValidateQuery(ref query, out empty);
                }
                bool flag = escapeSpecialChars;
                if (!flag) {
                    this.ResultsStats.Text = empty;
                    return;
                } else {
                    int num = 0;
                    int itemsToSkip = this.GetItemsToSkip();
                    int itemsToTake = this.GetItemsToTake();
                    SearchResults.ISearcher searcher = this.GetSearcher();
     
                    //THIS is the line that is broken - it just gets all items from index, and doesn't care about permissions...
                    //IEnumerable<IDocument> documents = searcher.Search(query, this.IndexCatalogue, itemsToSkip, itemsToTake, out num);
     
                    //Get ALL the results
                    var dirtyResults = searcher.Search(query, this.IndexCatalogue, 0, 0, out num);
     
                    //Filter out the duds - either by permission, or hardcoded pageID
                    var searchResults = new List<IDocument>();
     
                    //Managers
                    var libMgr = LibrariesManager.GetManager();
                    libMgr.Provider.SuppressSecurityChecks = true;
     
                    foreach (var result in dirtyResults) {
                        //NB: default to "TRUE" so that everything not explicitly handled will just show up as per normal
                        var validToDisplay = true;
                        var id = Guid.Parse(result.Fields.Single(f => f.Name == "Id").Value);
                        var contentType = result.Fields.Single(f => f.Name == "ContentType").Value;                       
     
                        switch (contentType) {
                            case "Telerik.Sitefinity.Pages.Model.PageNode":
                                //Here handle however you see fit if the page returned is valid for display in the search results
                                //Maybe loop UP the chain using page.Parent (or whatever) until you find the root "Products" page.  If that's the eventual Parent then it's valid to display
                                //With regards to By Department - maybe add a QueryString here to be the limiter (either Department Title or PageId) - if eventual Parent page matches by Id/Title then it's validToDisplay
                                var page = PageManager.GetManager().GetPageNodes().SingleOrDefault(o => o.Id == id);
                                validToDisplay = page != null && !page.Title.ToLower().Contains("NO DISPLAY");
                                break;
     
                            case "Telerik.Sitefinity.Libraries.Model.Document":
                                //Exists, is published and has permission
                                var doc = libMgr.GetDocuments().SingleOrDefault(d => d.Id == id && d.Visible && d.Status == ContentLifecycleStatus.Live);
                                validToDisplay = doc != null && doc.IsGrantedViewPermission();
                                break;
                        }
     
                        //Add to results if valid
                        if (validToDisplay) {
                            searchResults.Add(result);
                        }
                    }
     
                    //Setup the result variables
                    num = searchResults.Count;
     
                    //Setup to interact with paging
                    var searchResultsFiltered = searchResults.Skip(itemsToSkip).Take(itemsToTake);
     
                    char[] chrArray = new char[1];
                    chrArray[0] = '\"';
                    string str = this.Query.Trim(chrArray);
                    if (resultsStats != null) {
                        resultsStats.EnableViewState = false;
                        var stats = resultsStats.Text.Split(' ');
                        stats[0] = num.ToString();
                        resultsStats.Text = string.Join(" ", stats);
                    }
                    this.ConfigurePager(num);
                    this.ResultsList.DataSource = searchResultsFiltered;
                    return;
                }
            }
        }
     
        private int GetItemsToSkip() {
            if (this.AllowPaging) {
                int pageNumber = this.GetPageNumber(this.GetUrlEvaluationMode(), this.PageKey, 0, "PageNumber");
                if (pageNumber > 0) {
                    return (pageNumber - 1) * this.ItemsPerPage;
                }
            }
            return 0;
        }
     
        private int GetItemsToTake() {
            if (!this.AllowPaging) {
                return 0;
            } else {
                return this.ItemsPerPage;
            }
        }
    }

    Hope it helps and isn't too buggy!
  4. Daniel
    Daniel avatar
    19 posts
    Registered:
    08 Jan 2014
    14 Jan 2014
    Link to this post
    @Stephen2. This is great,   i'm still pretty new to sitefinity's syntax.  you said

    //THIS is the line that is broken - it just gets all items from index, and doesn't care about permissions...                
    //IEnumerable<IDocument> documents = searcher.Search(query, this.IndexCatalogue, itemsToSkip, itemsToTake, out num);         
           
     //Get ALL the results               
     var dirtyResults = searcher.Search(query,this.IndexCatalogue, 0, 0, out num);                 
    //Filter out the duds - either by permission, or hardcoded pageID

    any idea how the syntax is for parsing that information and or hard coding it? 
    thanks 
  5. Daniel
    Daniel avatar
    19 posts
    Registered:
    08 Jan 2014
    14 Jan 2014
    Link to this post
    Aswell,  What "namespace usings" do you have because that code gives me a few assembly reference errors. Noticeably  (dot)Single  which has literally 100's of possible definitions. 
  6. Stephen2
    Stephen2 avatar
    94 posts
    Registered:
    05 Feb 2012
    15 Jan 2014
    Link to this post
    Here's my usings, remove the custom Websilk ones:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using Telerik.Sitefinity.Services.Search.Web.UI.Public;
    using Telerik.Sitefinity.Services.Search.Data;
    using Websilk.Code;
    using System.Web.UI.WebControls;
    using System.Web.UI;
    using Telerik.Sitefinity.Security.Model;
    using Telerik.Sitefinity.Modules.Libraries;
    using Telerik.Sitefinity.GenericContent.Model;
    using Telerik.Sitefinity.Security;
    using Telerik.Sitefinity.Security.Configuration;
    using Telerik.Sitefinity.Modules.Pages;
    using Websilk.Sitefinity;
    using SitefinityWebApp.Websilk.Code;
    using System.Web.UI.HtmlControls;

    As for the syntax, note how I loop the "dirtyResults", extracting ID and ContentType, then getting each item using it's manager, then make decisions on whether to display it:
    //Filter out the duds - either by permission, or hardcoded pageID
    var searchResults = new List<IDocument>();
     
    //Managers
    var libMgr = LibrariesManager.GetManager();
    libMgr.Provider.SuppressSecurityChecks = true;
     
    foreach (var result in dirtyResults) {
        //NB: default to "TRUE" so that everything else will just show up as per normal
        var validToDisplay = true;
        var id = Guid.Parse(result.Fields.Single(f => f.Name == "Id").Value);
        var contentType = result.Fields.Single(f => f.Name == "ContentType").Value;                       
     
        switch (contentType) {
            case "Telerik.Sitefinity.Pages.Model.PageNode":
                //GetPageUrl function handles everything we need already - Security, Published, Show in Nav etc...
                var page = SitefinityFunctions.GetPageSiteNodeFromId(id, true);
                var pageUrl = SitefinityFunctions.GetPageUrl(page);
                validToDisplay = page != null && !page.Title.ToLower().Contains("collection item page") && !pageUrl.IsNullOrWhitespace();
                break;
     
            case "Telerik.Sitefinity.Libraries.Model.Document":
                //Exists, is published and has permission
                var doc = libMgr.GetDocuments().SingleOrDefault(d => d.Id == id && d.Visible && d.Status == ContentLifecycleStatus.Live);
                validToDisplay = doc != null && doc.IsGrantedViewPermission();
                break;
        }
     
        //Add to results if valid
        if (validToDisplay) {
            searchResults.Add(result);
        }
    }

    Beyond that you'll have to play around a bit!
  7. Markus
    Markus avatar
    2763 posts
    Registered:
    25 Nov 2005
    15 Jan 2014 in reply to Stephen2
    Link to this post
    Wouldn't it be nice if you could simply use a checkbox on the page properites like exclude form externen search engines - exclude from internal search engines

    I imagin this beeing so easy to do. Add one fieled in the page and then have the search engine of SF check if the box is checked or not.

    We have an PITS open since March 2011 requesting this and it has 59 votes. One of the top 5. Make it top 3 and we might get it :-) 

    http://www.telerik.com/support/pits.aspx#/public/sitefinity/5274

    So maybe you can vote for this, if you have not yet and Telerik might consider it for 7.x 

    Markus


  8. Daniel
    Daniel avatar
    19 posts
    Registered:
    08 Jan 2014
    15 Jan 2014 in reply to Markus
    Link to this post
    @markus 
    I placed a vote for you because it's a good idea. However,  it's not quite what we're after here. We're trying to search exclusively within contained portions of our own website, and exclude areas that are irrelevant, like being in the contact page you can search for 'an address' or what have you, but you will get no results if you you search for 'upcoming events'. 
  9. Markus
    Markus avatar
    2763 posts
    Registered:
    25 Nov 2005
    15 Jan 2014 in reply to Daniel
    Link to this post
    @Daniel

    Ok I thought it could be like this
    www.yourdomain.com/contact would have 'exclude from internal search' not checked
    www.yourdomain.com/events would have 'exclude from internal search' checked

    Thanks for the vote anyhow :-)

    Markus
  10. Boyko Karadzhov
    Boyko Karadzhov avatar
    56 posts
    Registered:
    05 Dec 2016
    17 Jan 2014
    Link to this post
    Hi,

    Daniel's thread has another solution posted for this case that may be helpful to some.

    I didn't see Svetla's blog post linked: http://www.sitefinity.com/blogs/svetla-yankovas-blog/2012/10/25/extending-sitefinity-search-and-searching-by-category

    It is not exactly the case that is discussed here but it is still a way to categorize search results.

    Regards,
    Boyko Karadzhov
    Telerik
    Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
10 posts, 0 answered