Tuesday, September 11, 2012

Using Search.asmx for People Search - SharePoint 2010


Scenario : Need to use SharePoint 2010 Out Of Box(OOB) Search.asmx to perform People Search from SharePoint profile data. Implement filters in search including phonetic search, refinements and use specific relevance model.

This is supposed to be relatively straight forward. You can consume the search services from any SiteCollection URL. For Ex: https://MyWebApp.com/sites/MySiteCollection/_vti_bin/search.asmx. You can prefix _vti_bin/search.asmx at any level (webapp/sitecollection/subsite) to consume the OOB web service. This is same as consuming any other OOB service in SharePoint.

You would use either Query or QueryEx methods based on whether you want your output in XML format or as a DataSet. In my scenario the data is required in an XML format. The Query method accepts a string input, which is an XML structure for SharePoint Query. For more details refer to Search Service on MSDN 

The Wrong Way, which works:

<?xml version="1.0" encoding="utf-8" ?>
<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  AccountName, Title, FirstName, 
      LastName,JobTitle, PreferredName, Manager, MobilePhone, WorkPhone, Department, 
      Function, Division, OrgDirect, OrgsManaged, Assistant, company, Country, region, 
      City, State, locationsitename, WorkEmail, Path, PictureURL, workassignment, 
      EmployeeType, Prefix, Pager, fax, PostalAddress1, PostalAddress2, PostalCode 
      FROM SCOPE() 
      WHERE ("DAV:contentclass" = 'urn:content-class:SPSPeople')   
      AND CONTAINS ('"John*"') AND ("Country" = 'USA')  
      AND ("peoplefinder" = 'display') ORDER BY "LASTNAME" ASC, "FIRSTNAME" ASC  </QueryText>
    </Context>
    <Range>
      <StartAt>1</StartAt>
      <Count>30</Count>
    </Range>
  </Query>
</QueryPacket>

The above query almost works at least in the above scenario. We are doing an all fields search for John and filtering the country by USA and getting the first 30 results of the result set. We can add more AND conditions in the QueryText if we need more filters.

However the problem comes when we want to include Phonetic Search Results or would need to apply a specific relevance model. As per the syntax on MSDN, its a straight forward like adding <EnablePhonetic>true</EnablePhonetic> after the Range attribute. However it doesn't work with the above approach. Any additional attributes like Stemming, Relevance Model will not work with the above structure.

The Right Way:
  
Below is the right way of consuming the Search.asmx for people search results. The difference is you apply a language attribute to the QueryText and provide the list of each of the properties you need.

<?xml version="1.0" encoding="utf-8"?>
<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">  John AND COUNTRY:"USA" AND  peoplefinder:"display" Scope:"People"</QueryText>
    </Context>
    <Properties>
      <Property name = 'AccountName'/>
      <Property name = 'Title'/>
      <Property name = 'FirstName'/>
      <Property name = 'LastName'/>
      <Property name = 'JobTitle'/>
      <Property name = 'PreferredName'/>
      <Property name = 'Manager'/>
      <Property name = 'MobilePhone'/>
      <Property name = 'WorkPhone'/>
      <Property name = 'Department'/>
      <Property name = 'Function'/>
      <Property name = 'Division'/>
      <Property name = 'OrgDirect'/>
      <Property name = 'OrgsManaged'/>
      <Property name = 'Assistant'/>
      <Property name = 'Company'/>
      <Property name = 'Country'/>
      <Property name = 'Region'/>
      <Property name = 'City'/>
      <Property name = 'State'/>
      <Property name = 'locationsitename'/>
      <Property name = 'WorkEmail'/>
      <Property name = 'Path'/>
      <Property name = 'PictureURL'/>
      <Property name = 'workassignment'/>
      <Property name = 'EmployeeType'/>
      <Property name = 'Prefix'/>
      <Property name = 'Pager'/>
      <Property name = 'fax'/>
      <Property name = 'PostalAddress1'/>
      <Property name = 'PostalAddress2'/>
      <Property name = 'Postalcode'/>
    </Properties>
    <Range>
      <StartAt>1</StartAt>
      <Count>30</Count>
    </Range>
    <EnableStemming>true</EnableStemming>
    <TrimDuplicates>true</TrimDuplicates>
    <IgnoreAllNoiseQuery>true</IgnoreAllNoiseQuery>
    <IncludeRelevanceResults>true</IncludeRelevanceResults>
    <IncludeSpecialTermResults>true</IncludeSpecialTermResults>
    <IncludeHighConfidenceResults>true</IncludeHighConfidenceResults>
    <EnablePhonetic>true</EnablePhonetic>
    <RelevanceModel>D9BFB1A1-9036-4627-83B2-BBD9983AC8A1</RelevanceModel>
  </Query>
</QueryPacket>

   The above XML Query works perfectly fine for all the filters including the RelevanceModel and Include/Exclude Phonetic results. 

2 comments:

  1. Great article and thanks for sharing, You are blog is more informative.




    SharePoint Development

    ReplyDelete
  2. It is very good and useful .Learned a lot of new things from your post!Good creation ,thanks for good info .Net Online Training

    ReplyDelete