Sitefinity 6 Search Indexes

Posted by Community Admin on 04-Aug-2018 16:28

Sitefinity 6 Search Indexes

All Replies

Posted by Community Admin on 12-Dec-2013 00:00

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!

Posted by Community Admin on 12-Dec-2013 00:00

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 -

Posted by Community Admin on 14-Dec-2013 00:00

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!

Posted by Community Admin on 14-Jan-2014 00:00

@Stephen2. This is great,   i'm still pretty new to sitefinity's syntax.  you said
[quote]
//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
[/quote]
any idea how the syntax is for parsing that information and or hard coding it? 
thanks 

Posted by Community Admin on 14-Jan-2014 00:00

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. 

Posted by Community Admin on 15-Jan-2014 00:00

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!

Posted by Community Admin on 15-Jan-2014 00:00

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 :-) 

www.telerik.com/.../pits.aspx

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

Markus


Posted by Community Admin on 15-Jan-2014 00:00

@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'. 

Posted by Community Admin on 15-Jan-2014 00:00

@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

Posted by Community Admin on 17-Jan-2014 00:00

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

This thread is closed