How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Posted Sunday, August 15, 2010 9:46 PM by CoreyRoth

Last week, I talked about the KeywordQuery class and how to use it in SharePoint 2010.  I mentioned that a new way to query also existed using the QueryManager class.  This class is extremely powerful and can allow us to issue federated queries to multiple locations at one time.  For example, you could make one call and get results back simultaneously from Enterprise Search, FAST, and an OpenSearch provider like Bing.  You can still use the KeywordQuery class but I think the best practice is likely to be the QueryManager class because of the added flexibility.  Another thing I like about the QueryManager class is that the results are returned as XML instead of a ResutlsTableCollection.  Now, in reality if you are just querying one source such as Local Search Results, QueryManager might add a little overhead since it turns around and calls the KeywordQuery class, but I think the the benefits that QueryManager brings are worth it.

Before we begin, let’s take a look at our Federated Locations in the Search Service Application.  In a typical out-of-the-box SharePoint 2010 install, you will have five Federated Locations.  We can query any of these locations using the QueryManager class.  However, we have to know the proper name to pass to the QueryManager to specify the location.  We’ll talk about that here in a bit.  Here is what your federated locations might look like.  In my case, I have an extra federated location that I created myself that queries search on DotNetMafia.com.

FederatedLocationsList

For our first example, we will just issue a simple query against the Local Search Results location.  Our first couple of lines are just like the ones we used with the KeywordQuery claass.  We need a reference to the Search Service Application.  In my case, I have named my application Search Service Application.  Change the name of the string to match the name of your service application.

// get the query and settings service proxy

SearchQueryAndSiteSettingsServiceProxy settingsProxy = SPFarm.Local.ServiceProxies.GetValue<SearchQueryAndSiteSettingsServiceProxy>();

 

// get the search service application proxy by name

SearchServiceApplicationProxy searchProxy = settingsProxy.ApplicationProxies.GetValue<SearchServiceApplicationProxy>("Search Service Application");

We now need to create an instance of the QueryManager object as well as an object to keep track of the locations we are searching (LocationList).  The QueryManager is kind of an interesting object because it really is just a LocationList with a few extra properties.  There are very few settings you can specify on it other than the query.   Both of these just use default constructors, we pass in the proxy once we start creating new Location objects.

QueryManager queryManager = new QueryManager();

LocationList locationList = new LocationList();

Now, we want to create an instance of a Location object which takes the internal name of the location of the federated location as well as our SearchServiceApplicationProxy.  The example in the SDK had a heap of code, that loops through all of the locations on the server.  I found that it was kind of overkill and can simply be replaced with a single line of code to create the Location object.

Location localSearchLocation = new Location("LocalSearchIndex", searchProxy);

As you can see here, I specified LocalSearchIndex for the name of my Location.  You might be wondering where I got that value.  This is the internal name of the federated location (not to be confused with the display name).  You can get this value by looking at the details of the location.

FederatedLocationLocalSearchIndex

Here is a table with the internal names of all of the out-of-the-box federated locations for future reference.

Display Name Internal Name
Internet Search Results InternetSearchResults
Internet Search Suggestions InternetSearchSuggestions
Local Search Results LocalSearchIndex
Local People Search Results LocalPeopleSearchIndex
Local FAST Search Results FASTSearch

As you can see there is not a lot of consistency between the internal names so I thought this table would be useful.  Remember, we can query FAST using the same API as we do Enterprise Search.  We just specify FASTSearch as the location.  We’ll talk about that more in a future post as well.  Now, we need to add the location to the LocationList.

locationList.Add(localSearchLocation);

Once we have a location set, we can actually specify our query.  We’ll stick with my usual example of querying for accounting documents.

queryManager.UserQuery = "accounting";

Now we just need to add our LocationList to our QueryManager and we’re ready to query.  We also have to pass it to the IsTriggered method as well.  I’m not fully sure of the reason behind this, but I think if you don’t set it, the location will be added but not executed.

queryManager.Add(locationList);

queryManager.IsTriggered(locationList);

Now we execute the query using the GetResults method.  It returns an XmlDocument class.  I am kind of surprised this isn’t an XDocument, but I guess it’s easy enough to get from one to the other.

XmlDocument xmlDocument = queryManager.GetResults(locationList);

If you have everything configured successfully, you should get some XML with results.  Let’s take a look at what one of the results looks like.  I make use of the File object’s WriteAll method to quickly dump the results into an XML file so I can look at it.  That was one of my first blog posts there more than five years ago. :-)  This way I can open it with Visual Studio and use the Format Document (Ctrl+K, Ctrl+D) command to make it readable.  Here is what one of the results looks like.

<Result>

  <id>2</id>

  <workid>125</workid>

  <rank>76221694</rank>

  <title>Accounting Procedures 2009</title>

  <author_multival>Craig Johnson</author_multival>

  <author_multival>Windows User</author_multival>

  <author>Craig Johnson;Windows User</author>

  <size>22341</size>

  <url>http://sp2010/ECM/Company Documents/Accounting Procedures 2009.docx</url>

  <urlEncoded>http%3A%2F%2Fsp2010%2FECM%2FCompany%20Documents%2FAccounting%20Procedures%202009%2Edocx</urlEncoded>

  <description></description>

  <write>7/20/2010</write>

  <sitename>http://sp2010/ECM/Company Documents</sitename>

  <collapsingstatus>0</collapsingstatus>

  <hithighlightedsummary>

    This document details all <c0>accounting</c0> policies and procedures for fiscal year 2009.

  </hithighlightedsummary>

  <hithighlightedproperties>

    <HHTitle>

      <c0>Accounting</c0> Procedures 2009

    </HHTitle>

    <HHUrl>

      http://sp2010/ECM/Company Documents/<c0>Accounting</c0> Procedures 2009.docx

    </HHUrl>

  </hithighlightedproperties>

  <contentclass>STS_ListItem_DocumentLibrary</contentclass>

  <isdocument>True</isdocument>

  <picturethumbnailurl></picturethumbnailurl>

  <serverredirectedurl>http://sp2010/ECM/_layouts/WordViewer.aspx?id=/ECM/Company%20Documents/Accounting%20Procedures%202009.docx&amp;DefaultItemOpen=1</serverredirectedurl>

</Result>

This is all of the data you get back without specifying any custom managed properties.  If you are familiar with querying Enterprise Search from MOSS 2007, you will know that there is a lot more data returned.  I’ll point out some of the interesting elements.  When a document has multiple authors, we see them all in author element delimited by a semicolor (;).  Each author is also available separately in the author_multival element.  Of course, we have the usual things such as a URL, the size, modification date (write), whether it is a document or not, and it’s content class.  The sitename element is particularly interesting.  It actually gives us the folder that the file exists in.  You don’t know how much I wanted that feature in MOSS 2007.  That is why I wrote the document link handler to help get the folder name of documents.  If you use Excel Services or Office Web Apps, the serverredirectedurl will provide the path to open the document using Office Web Apps.

I would be a bad blogger if I didn’t tell you how to specify your own managed properties.  Unfortunately, this works exactly like it did in SharePoint 2007.  If you specify one managed property, you lose all of the defaults.  You’ll see what I mean here in a minute.  You specify your managed properties on the Location object using the RequestedProperties StringCollection.  Just set the property on the Location before adding it to the LocationList.

localSearchLocation.RequestedProperties = new System.Collections.Specialized.StringCollection() { "DocumentType" };

Since I didn’t specify any other managed properties, the only thing I get back is the Id and the DocumentType managed properties.  See below.

<Result>

  <id>2</id>

  <documenttype>Accounting</documenttype>

</Result> 

Not very useful.  So instead, you have to pass the values of all of the fields you want.  I have found that most of the elements you see in the first XML document, you can pass to the RequestedProperties parameter but not all of them.  For example, to get the value of the URL, you actually specify the manager property path, and it gives you both url and urlEncoded.  Here is what the line might look to get all of your managed properties and the new one. 

localSearchLocation.RequestedProperties = new System.Collections.Specialized.StringCollection()

{ "workid", "rank", "title", "author", "size", "write", "path", "sitename", "description",

    "CollapsingStatus", "HitHighlightedSummary", "HitHighlightedProperties", "ContentClass",

    "IsDocument", "PictureThumbnailURL", "PopularSocialTags", "PictureWidth", "PictureHeight",

    "DatePictureTaken", "ServerRedirectedURL", "DocumentType" };

How did I know all of those properties?  Well the URL thing I remember from working with the KeywordQuery class in the past.  The rest, I just got from the CoreResutlsWebPart.  You can also look at the Local Search Results federated location.

FederatedLocationLocalSearchIndexManagedProperties

I was planning on showing the code to do multiple locations too, but this post is already getting long, so I think I will include it in the next post.  It’s cool enough to deserve its own post. :-)  I will show you two other properties that are important to know about.  These properties allow us to do paging.  On the Location object we can set the ItemsPerPage and StartItem property to set the number of items per page and what item to start on.  For example, to start on item #21 and show 20 items, we would add the following before the Location is added to the LocationList.

localSearchLocation.ItemsPerPage = 20;

localSearchLocation.StartItem = 21;

When you get results back, the XML contains the total number of results as well as the number of results returned.  In my case I only had two results in my set since there were only 22 items in the entire set.

  <TotalResults>22</TotalResults>

  <NumberOfResults>2</NumberOfResults>

</All_Results>

I assume these number are estimates in Enterprise Search, but I could be wrong.  I need to test more.  If you know for sure, please leave a comment. 

One more thing I will mention is that exceptions are returned by the Location object.  So if you don’t get results back, check Location.Exception to see what the details are.  It won’t actually throw an exception.  It will just return null.

I know some people (including myself) like to see all of the code together, so here it is.  This is the complete example with our DocumentType managed property included with paging.

// get the query and settings service proxy

SearchQueryAndSiteSettingsServiceProxy settingsProxy = SPFarm.Local.ServiceProxies.GetValue<SearchQueryAndSiteSettingsServiceProxy>();

 

// get the search service application proxy by name

SearchServiceApplicationProxy searchProxy = settingsProxy.ApplicationProxies.GetValue<SearchServiceApplicationProxy>("Search Service Application");

 

// create QueryManager and LocationList objects

QueryManager queryManager = new QueryManager();

LocationList locationList = new LocationList();

 

// add the federated location we want

Location localSearchLocation = new Location("LocalSearchIndex", searchProxy);

 

// set the start page and page size

localSearchLocation.ItemsPerPage = 20;

localSearchLocation.StartItem = 21;

 

// add our managed properties

localSearchLocation.RequestedProperties = new System.Collections.Specialized.StringCollection()

{ "workid", "rank", "title", "author", "size", "write", "path", "sitename", "description",

    "CollapsingStatus", "HitHighlightedSummary", "HitHighlightedProperties", "ContentClass",

    "IsDocument", "PictureThumbnailURL", "PopularSocialTags", "PictureWidth", "PictureHeight",

    "DatePictureTaken", "ServerRedirectedURL", "DocumentType" };

 

// add the Location to the LocationList

locationList.Add(localSearchLocation);

 

// set the query

queryManager.UserQuery = "accounting";

queryManager.Add(locationList);

queryManager.IsTriggered(locationList);

 

// make the call to search

XmlDocument xmlDocument = queryManager.GetResults(locationList);

 

// write out the results

System.IO.File.WriteAllText("results.xml", xmlDocument.InnerXml);

Console.WriteLine(xmlDocument.InnerXml);

Console.ReadLine();

The QueryManager class is very powerful for interacting with Enterprise Search.  I hope you found this post useful.  In my next post, we’ll query multiple locations at a time.

Comments

# Twitter Trackbacks for How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search - Corey Roth - DotNetMafia.com - Tip of the Day [dotnetmafia.com] on Topsy.com

Pingback from  Twitter Trackbacks for                 How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search - Corey Roth - DotNetMafia.com - Tip of the Day         [dotnetmafia.com]        on Topsy.com

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Friday, August 27, 2010 2:56 AM by Marc

Hi Corey

Thanks for this really helpful article!

I wonder if it is possible to set a sort order and sort direction using the QueryManager approach? Or is this only possible using the KeywordQuery class? I need the results in XML so the QueryManager would be my prefered way...

Regards, Marc

# Changing The Name of The People Search Scope &#8211; Umpossible? | SharePoint Blues

Pingback from  Changing The Name of The People Search Scope &#8211; Umpossible? | SharePoint Blues

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Monday, November 8, 2010 1:49 AM by Mikael Svenson

Is it possible to use the fql capabilities of the KeywordQuery class somehow with the QueryManager?

Getting xml is in many cases nicer than a datatable and if I can skip rendering xml myself from the datatable that's less code and complexity :)

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Monday, November 8, 2010 9:03 AM by CoreyRoth

@Mikael It should be (since we know that is how CoreResultsWebPart) does it.  It's actually on my list of topic for future blog posts but I haven't gotten to it yet.

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Monday, November 29, 2010 9:12 AM by Stephan

Hi Corey, thank you for this very helpful article! Is it possible to limit search to specific document types i.e. images?

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Monday, November 29, 2010 9:18 AM by CoreyRoth

@ You could use the FileType keyword to return specific file types.  See this post for more information.

www.dotnetmafia.com/.../some-handy-keywords-you-might-find-useful-in-sharepoint-enterprise-search.aspx

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Wednesday, February 16, 2011 10:59 AM by RoelBSS

Hi Corey,

Finally a chance to post this question! We already spoke on the msdn forum about a ToolPart thingy.

The other problem I am having is the following: I want to use the QueryManager to take full control of my CustomCoreResultsWebPart and fire my query to our FAST server via the QueryManager rather than setting the FixedQuery property for the Web Part. I have prepared a string to be used as a search query and followed your code in the article. In my case I want to output the results of the query directly to the screen (customization with templates and so on will be implemented later), so I am overwriting the RenderWebPart method. Now I am not sure if I should be issuing the query in the QueryManager (GetResults) in this method, but well.. Anyway, the XmlDocument keeps on coming back empty, and I don't understand why. My location is there, my querystring is set, but queryManager.Getresults(locationList) does not seem to give anything back.. what could I be doing wrong? Thanks in advance!

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Thursday, February 17, 2011 2:36 AM by RoelBSS

Hi Corey,

Following your code example, the xmlDocument = queryManager.GetResults(locationList) keeps on getting back empty. Location and Querymanager are initialised ok, and setting the query as FixedQuery (which is what I don't want to do) is working just fine. Any idea what I could be doing wrong? Trying to do this all in an override of the RenderWebPart method.

Regards,

Roel

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Thursday, February 17, 2011 8:43 AM by CoreyRoth

@RoelBss Start by verifying that you have the location name and search service application names correct.  Then verify inside SharePoint itself that your query works if you haven't already.  Also try a query that returns the entire content source (i.e.: ContentSource:"Local SharePoint Sites").

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Friday, February 18, 2011 3:37 AM by RoelBSS

Ok, done that! location name is the standard location for fast search: "FASTSearch" and I'm getting the search proxy like this: SearchServiceApplicationProxy searchProxy = (SearchServiceApplicationProxy)SearchServiceApplicationProxy.GetProxy(SPServiceContext.GetContext(SPContext.Current.Site));, which gives me back the correct SSA name.

I may have to add that I am overwriting the datasource and datsourceview to enable some extra searchproperties (like fql). In which method should I put the QueryManager code?

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Friday, February 18, 2011 4:13 AM by RoelBSS

debugging now: I am getting a "Property doesn't exist or is used in a manner inconsistent with schema settings" exception in the FastSearchRuntime method "GetResults", where the xml is filled with the command: queryResult = this.GetQueryResult(query);

Is this the result of bad initialization of my Querymanager?

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Monday, February 21, 2011 6:37 AM by RoelBSS

solved: one needs to specify a different set of properties for a FAST search location for the querymanager to be able to get the results. So now I have the XmlDocument containing the results of my search, how can I display them in a nice way? If I just write out the innerxml it looks terrible, I would like the "normal" xml markup as my output.

thanks!

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Monday, February 21, 2011 9:47 AM by CoreyRoth

@Roel probably the easiest way is with an XSL transformation.  It will allow you to take the XML and transform it into usable HTML.

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Monday, February 21, 2011 10:34 AM by RoelBSS

nope, that's one of my requirements, to do this without xslt. but no matter, I've figured it out. I get my xmlResultDoc in the GetXPathNavigator override, and then override the RenderWebParts method to write out just my xmlResultDoc with some extra info (xml open and close/xmp tag). Now it's just the same output as if if put an xslt transformation over the results that would output pure xml! thanks so much for all the help!!

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Tuesday, February 22, 2011 6:23 AM by RoelBSS

I thought I was finished with this topic, but a question still remains: I want to integrate my Custom Web Part that uses the Querymanager to get xml results with the standard Search Web Parts, like Search Paging. Now I am instantiating my QueryManager like so: QueryManager queryManager = SharedQueryManager.GetInstance(Page, base.QueryNumber).QueryManager, so that I have an instance for a specific QueryID of the Querymanager. When I add the SearchPagingWebPart however, and set it to the same ID (2 in my example case is the QueryID for the base Web Part) it doesn't show me any paging options. Anything I am forgetting here?

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Tuesday, February 22, 2011 8:40 AM by CoreyRoth

@Roel I'm not sure there.  I think it should work as long as the QueryID is the same, but there may be something else as you suspect.

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Tuesday, February 22, 2011 9:08 AM by RoelBSS

The weird thing is, it seems to work when my searchlocation is "InternetSearchResults", at least the Search Paging Web Part appears. The paging doesn't work though, it keeps on showing the same page when I click the link for "next" or a page number. For locations other than "InternetSearchResults" it doesn't show at all. Not really understanding this..

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Thursday, June 23, 2011 7:06 AM by Rahul

Hi Corey,

I did everything that you mentioned in your post but i keep getting an error regarding assembly:

'Microsoft.Office.Server.Search.Administration.SearchQueryAndSiteSettingsServiceProxy' from assembly 'Microsoft.Office.Server.Search, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c'.

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Friday, July 8, 2011 4:25 PM by CoreyRoth

@Rahul what error are you getting?

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Monday, August 1, 2011 10:24 AM by RoelBSS

Hi Corey, any pointers on how to instantiate and use the RefinementManager, so that I could add custom refiners to the query I am issueing?

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Thursday, August 4, 2011 9:05 AM by CoreyRoth

@RoelBSS I'm afraid I haven't worked with it much yet.  It's on my to-do list of things to figure out.

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Tuesday, November 29, 2011 12:13 AM by John

Hi Corey,

Really helpful article!

Solves my problem on IDs.

Regards,

John

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Wednesday, September 12, 2012 12:38 AM by Kamagurka

Hi Corey,

Although I reference Microsoft.Office.Server.Search from the 14/ISAPI hive, I lack SearchQueryAndSiteSettingsServiceProxy as a using option. Might it be that I've overlooked to install something on my farm? I can't select Microsoft.Office.Server.Search.Administration.SearchQueryAndSiteSettingsServiceProxy as it's not available for some obscure reason?

Question: Have you come across this before, can you please point me in the right direction?

I hope this post is still open?

Kind regards, W

# re: How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search

Thursday, September 13, 2012 10:19 AM by CoreyRoth

That assembly is only available if you have SharePoint Server.  If you are using SharePoint Foundation, it will not be present (unless you add Search Server Express).

# Getting Elevated Search Results in SharePoint 2010 | SharePoint interests

Pingback from  Getting Elevated Search Results in SharePoint 2010 | SharePoint interests

# savewallpap.com

Thursday, October 16, 2014 7:24 PM by savewallpap.com

How to: Use the QueryManager class to query SharePoint 2010 Enterprise Search - Corey Roth [MVP]

Leave a Comment

(required) 
(required) 
(optional)
(required)