Monday, August 26, 2013

Accessing rank models in SharePoint 2010

I recently blogged about rank models in SharePoint 2013, and how you can use PowerShell to dump the existing rank model XML.
The commandlets to do so are more or less same as for SharePoint 2010, with one important difference, the RankingModelXML attribute is empty in 2010 (in most cases – more on that below).
$ssa = Get-SPEnterpriseSearchServiceApplication
Get-SPEnterpriseSearchRankingModel -SearchApplication $ssa | select RankingModelXML

RankingModelXML
---------------


The reason for this is not obvious at first, but it is if you look at the set’er of this property with something like Reflector. Code is shortened for readability, and may be found in Microsoft.Office.Server.Search.dll for the RankingModel class.

CustomRankingModel customRankingModel = new CustomRankingModel(value);
if (!(customRankingModel.ID == this.id))
  throw new InvalidOperationException(StringResourceManager.GetString(LocStringId.RankingModel_CannotChangeIdException_Message));
this.internalModelXml = customRankingModel.ConvertToInternalModelXml();
this.customModelXml = customRankingModel.RankingModelXML;

As you can see from the code above the pre-set rank model xml resides in the property InternalModelXml. Any changes you decide to make to the model will appear in the customModelXml field which is what RankingModelXML returns.

If you want to get hold of the existing rank model from one of the oob models, you have to either resort to querying the SQL base as posted by others in the web, or you can use reflection.

In C# it would look like this:

SearchService service = SearchService.Service;
var ssa = service.SearchApplications.First() as SearchServiceApplication;
Ranking rank = new Ranking(ssa);
PropertyInfo propertyInfo = typeof(RankingModel).GetProperty("InternalModelXml", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

foreach (RankingModel rankingModel in rank.RankingModels)
{
    string rankingModelXML = propertyInfo.GetValue(rankingModel, null) as string;
    Console.WriteLine(rankingModelXML);
}

Or in PowerShell:

[void][reflection.assembly]::Loadwithpartialname("Microsoft.office.server.search") | out-null

$ssa = Get-SPEnterpriseSearchServiceApplication
$bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic"
$prop = [Microsoft.Office.Server.Search.Administration.RankingModel].GetProperty("InternalModelXml", $bindingFlags)
Get-SPEnterpriseSearchRankingModel -SearchApplication $ssa | foreach { $prop.GetValue($_, $null) }