Sitefinity 6 Search Indexes
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!
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 -
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;
@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
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.
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;
//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);
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
@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'.
@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
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