How to: Query Search using the Web Service
Posted
Thursday, July 17, 2008 2:49 PM
by
CoreyRoth
According to FeedBurner, my posts on querying Enterprise Search with the FullTextSqlQuery and KeywordQuery classes have been some of the most popular. So I thought, I would continue on these posts and explain how to do it using the web service. The SDK covers this, but not in enough detail for me. When I am learning something new, I like to see complete examples, so hopefully this will help someone trying to learn how to do this. The first place to start is by adding a web reference to your project. You can query SharePoint Search or Enterprise Search in the exact same manner it is just a matter of which web service you make a reference to. SharePoint search can be queried at a URL similar to the one below.
http://moss-server/_vti_bin/spsearch.asmx
To query Enterprise Search, the URL will look similar to this. Both web services have the same methods. They just query different indexes.
http://moss-server/_vti_bin/search.asmx
To execute a query, you have to build an XML document. I posted about the XML you post to the service in the past, now I will give a complete example and then also explain some of the options you can configure when querying. The type of query is specified on the QueryText element using the Type attribute. A value of MSSQLFT like in the XML below is used to do a full text query.
<QueryPacket xmlns="urn:Microsoft.Search.Query" Revision="1000">
<Query domain="QDomain">
<SupportedFormats>
<Format>urn:Microsoft.Search.Response.Document.Document</Format>
</SupportedFormats>
<Context>
<QueryText language="en-US" type="MSSQLFT">SELECT Title, Path, Description, Write, Rank, Size FROM Scope() WHERE CONTAINS('Accounting') AND "Scope" = 'Corporate Documents'</QueryText>
</Context>
</Query>
</QueryPacket>
In the example above, I have a simple query that is looking for documents with the word Accounting in the Corporate Documents scope. Issuing a keyword query is similar but it uses a Type of STRING. In this example, we are searching on the managed property city with a value of Austin.
<QueryPacket xmlns="urn:Microsoft.Search.Query" Revision="1000">
<Query domain="QDomain">
<SupportedFormats>
<Format>urn:Microsoft.Search.Response.Document.Document</Format>
</SupportedFormats>
<Context>
<QueryText language="en-US" type="STRING">City:"Austin"</QueryText>
</Context>
</Query>
</QueryPacket>
There are two methods used to query search. The Query method returns the results as XML. The QueryEx method returns the results as an ADO.NET dataset. They both take the same input XML document like the ones above. The code is pretty simple. Here I create a new reference to the web service (I named it QueryWebService) and I pass it credentials. Like any SharePoint web service, you have to pass it credentials. You can specify custom ones or just use the credentials of the application you are running using DefaultCredentials.
QueryWebService.QueryService queryService = new QueryWebService.QueryService();
queryService.Credentials = System.Net.CredentialCache.DefaultCredentials;
For this example, I am just going to build the input XML using a StringBuilder.
queryXml.Append("<QueryPacket xmlns=\"urn:Microsoft.Search.Query\" Revision=\"1000\">");
queryXml.Append("<Query domain=\"QDomain\">");
queryXml.Append("<SupportedFormats>");
queryXml.Append("<Format>");
queryXml.Append("urn:Microsoft.Search.Response.Document.Document");
queryXml.Append("</Format>");
queryXml.Append("</SupportedFormats>");
queryXml.Append("<Range>");
queryXml.Append("<Count>50</Count>");
queryXml.Append("</Range>");
queryXml.Append("<Context>");
queryXml.Append("<QueryText language=\"en-US\" type=\"STRING\">");
queryXml.Append("City:\"Austin\"");
queryXml.Append("</QueryText>");
queryXml.Append("</Context>");
queryXml.Append("</Query>");
queryXml.Append("</QueryPacket>");
This query is similar to the one from above, but I added a Range and Count element. By default, you will only get 10 results back, by changing this element I will get back 50 in this case. You can also specify a StartAt element to start on a specific row. This would be useful if you are building paging into something. Then I just execute the query like so.
string resultXml = queryService.Query(queryXml.ToString());
This returns an XML document that looks similar to the following.
<ResponsePacket xmlns="urn:Microsoft.Search.Response">
<Response domain="QDomain">
<Range>
<StartAt>1</StartAt>
<Count>10</Count>
<TotalAvailable>7312</TotalAvailable>
<Results>
<Document relevance="1000" xmlns="urn:Microsoft.Search.Response.Document">
<Title>Document 1</Title>
<Action>
<LinkUrl size="0">http://moss-server/Documents/Document1.docx</LinkUrl>
</Action>
<Description />
<Date>2008-07-15T19:59:43.2511787-05:00</Date>
</Document>
<Document relevance="1000" xmlns="urn:Microsoft.Search.Response.Document">
<Title>Document 2</Title>
<Action>
<LinkUrl size="0">http://moss-server/Documents/Document2.docx</LinkUrl>
</Action>
<Description />
<Date>2008-07-15T19:59:43.2511787-05:00</Date>
</Document>
</Results>
</Range>
<Status>SUCCESS</Status>
</Response>
</ResponsePacket>
From here, you have something that you can easily work with using LINQ to XML. If you are feeling lazy, you can always just use QueryEx to get a dataset as well. You can configure quite a few options in how things are searched using the input XML document. The schema is in the SDK if you are interested. Hopefully, this will help the next time you need to query search.