Monday, August 10, 2009

MOSS Advanced Search Queries

We recently had to determine the search queries fired when one used the OOB SharePoint Advanced Search Web Part. This was while working on an implementation of faceted search results, where we were getting different count of search results for Faceted and Advanced Search. The only way to make the results match was make both the web parts fire the same queries, and have similar settings for Duplicates, Noise words and stemming. First I will tell you the queries, and then I will talk about how did I extract them. Searching for my company name “MAQ Software” and selecting “MyCustomScope” forms the queries as:


All of these words:
SELECT WorkId, Rank, Title, Author, Size, Path, Description, Write, SiteName, CollapsingStatus, HitHighlightedSummary, HitHighlightedProperties, ContentClass, IsDocument, PictureThumbnailURL from scope() where freetext(defaultproperties,'+MAQ +Software') And ("scope" = 'MyCustomScope' Or "scope" = 'MyCustomScope')

The exact phrase:
SELECT WorkId, Rank, Title, Author, Size, Path, Description, Write, SiteName, CollapsingStatus, HitHighlightedSummary, HitHighlightedProperties, ContentClass, IsDocument, PictureThumbnailURL from scope() where freetext(defaultproperties,'+"MAQ Software"') And ("scope" = 'MyCustomScope' Or "scope" = 'MyCustomScope')


Any of these words:
SELECT WorkId, Rank, Title, Author, Size, Path, Description, Write, SiteName, CollapsingStatus, HitHighlightedSummary, HitHighlightedProperties, ContentClass, IsDocument, PictureThumbnailURL from scope() where freetext(defaultproperties,'MAQ Software') And ("scope" = 'MyCustomScope' Or "scope" = 'MyCustomScope')


None of these words:
SELECT WorkId, Rank, Title, Author, Size, Path, Description, Write, SiteName, CollapsingStatus, HitHighlightedSummary, HitHighlightedProperties, ContentClass, IsDocument, PictureThumbnailURL from scope() where freetext(defaultproperties,'-MAQ -Software') And ("scope" = 'MyCustomScope' Or "scope" = 'MyCustomScope')

I won’t go into the details of freetext clause or the significance of “+” or “-”sign in this blog. There are other articles on the net which describe the same in great detail.

To extract the queries, I started using Lutz .NET Refelctor and digging into the CoreResultsWebPart, which is found in the assembly Microsoft.Office.Server.Search. The CoreResultsWebPart class is a lazy guy, and relies on Microsoft.Office.Server.Search.WebControls.SearchResultHiddenObject to do most of the work. On closer study of the SearchResultHiddenObject class methods and fields, it can be seen that after composition, the search query gets saved in the field _fullTextQuery

I decided to create a custom web part, which inherits from CoreResultsWebPart, and read the query formed. However, the authors of SearchResultHiddenObject decided to make the class internal and this complicated things a bit. On trying to create an object reference of SearchResultHiddenObject, it gave the expected error message “SearchResultHiddenObject is inaccessible due to its protection level”. Object oriented boundaries can be broken and private and internal fields accessed using .NET reflection. That is what I did to get the above queries.

The approach is similar to the one described in Corey Roth’s blog, but you should write your code in the OnPreRender event. The query is not fully composed when other events earlier in the web part lifecycle are called.


Same logic can be used to find the queries fired by basic or people search, and you can give it a try.