Wednesday, May 4, 2011

Working with crawled and managed properties via code

I was teaching a FAST for SharePoint Workshop today and we were doing labs on creating and mapping crawled properties to managed properties with the FAST Administration UI and via PowerShell. But one student wanted to know how to do this in code, hence this blog post.

Instead of having a deployment script creating your properties, you could have an event receiver which creates your mappings once a site or list is provisioned. Or when some other action is going on.

So how do you go about doing this?

Well, first off Crawled and Managed Properties for FAST are a part of the index schema and is accessible via the following two namespaces:

Microsoft.SharePoint.Search.Extended.Administration Microsoft.SharePoint.Search.Extended.Administration.Schema

which are the namespaces used for working with the FAST components. But first you have to get an instance of the WCF client proxy on the SharePoint side used to communicate with the FAST for SharePoint farm. This is accomplished via the FASTAdminProxy property of the search application proxy.

Below is a quick example showing how this can be done in code, with comments along the way to guide the process. It’s all pretty straight forward.

const string propertyName = "productname";
// Get a reference to the proxy and the Index Schema
var ssaProxy = (SearchServiceApplicationProxy)SearchServiceApplicationProxy.GetProxy(SPServiceContext.Current);

SchemaContext schemaContext = ssaProxy.FASTAdminProxy.SchemaContext();
Schema schema = schemaContext.Schema;

// Assign a guid to the custom Crawled Propery Category
Guid myGuid = new Guid(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
Category catGroup;
// Create if it does not exist
if (!schema.AllCategories.Contains(myGuid))
{
    catGroup = schema.AllCategories.Create("My Crawled Properties", myGuid);
}
else
{
    catGroup = schema.AllCategories[myGuid];
}

// Create a new crawled property if it doesn't exist
CrawledProperty cp = catGroup.GetAllCrawledProperties().Where(
    c => c.Name == propertyName && c.VariantType == 31 && c.Propset == myGuid).FirstOrDefault();
if (cp == null) cp = catGroup.CreateCrawledProperty(propertyName, myGuid, 31);

// Create a new managed property if it doesn't exist
ManagedProperty mp;
if (!schema.AllManagedProperties.Contains(propertyName))
{
    mp = schema.AllManagedProperties.Create(propertyName, "", ManagedType.Text);
}
else
{
    mp = schema.AllManagedProperties[propertyName];
}

// Create a new crawled to managed property mapping if it doesn't exit
CrawledPropertyMapping mapping = mp.GetCrawledPropertyMappings();
if (!mapping.Contains(cp))
{
    mapping.Add(cp);
    mp.SetCrawledPropertyMappings(mapping);
}

// Get a reference to the default full text index (first one)
FullTextIndex fti = schema.AllFullTextIndecies.First();

// Get the full text index mapping from the Managed Property
FullTextIndexMappingCollection fullTextIndexMappingCollection = mp.GetFullTextIndexMappings();
FullTextIndexMapping indexMapping =
    fullTextIndexMappingCollection.Where(ftpMap => ftpMap.FullTextIndex.Name == fti.Name).FirstOrDefault();
// Set a mapping to importance level 6, if it's not already set to something else
if (indexMapping == null || !fullTextIndexMappingCollection.Contains(indexMapping))
{
    fullTextIndexMappingCollection.Create(fti, 6);
}

10 comments:

  1. Juha-Pekka PulkkinenMay 5, 2011 at 9:00 AM

    Excellent. Just what I was looked for. Thank you!

    ReplyDelete
  2. Hi Mikael,

    Nice Post!
    Can we setup a crawl rule to perform indexing on historic versions of document in SharePoint. SharePoint runs crawl on only last approved version of a document and accordingly it display only latest versions in search result and skip all historic version having matching search criteria. One of my client have requirement that each piece of matching content should appear in search result no matter it is latest or historic.
    From there business need there point is very reasonable. I explored possibility of custom solution to implement this but not found any help available. Although I have found a product which enables version search in SharePoint 2010 and FAST. Demo at their site http://stoictech.sharepoint.com/Pages/VersionSearch.aspx looks promising. Do you know about any other better solution or product which can enable version search.
    Thanks for your help.
    Vikas

    ReplyDelete
  3. Hello Vikas,
    I actually got a call from FAST/Microsoft about this yesterday :) Where they asked if I knew any solution to this. As they found out it has been a design decision to only index the latest version in the SharePoint crawler. The reason is that most users would be confused if they got many versions of a document. But I think as long as you present it in a good way in the UI it should work fine.

    I don't know of any other way myself, except the product you refer to, which is what I referred them to. I haven't tried it or explored it myself, so I'm not sure how they do it.

    ReplyDelete
  4. Hi Mikael!
    Thank you for post. I have a question related to managed properties - is it possible set value for particular managed property for indexed file? For example I have a file, that has been already indexed, I have managed property "My prop". I know that crawled properties mapped to managed properties, and managed property contains value from one (or many) crawled properties. But I want to setup managed property for file after indexing. Is it possible?
    Thanks in advance.

    ReplyDelete
  5. Hi Kai,
    If you want to assign a custom value to a managed property you have to do so during indexing. You can create a custom extensibility stage which assign the value to a crawled property which you map to the managed property.

    The values of the managed properties are stored in the index, thus they have to be assigned during indexing.

    ReplyDelete
    Replies
    1. "If you want to assign a custom value to a managed property you have to do so during indexing. You can create a custom extensibility stage which assign the value to a crawled property which you map to the managed property."
      Yep, I know it, but I want to assign value to a managed property after indexing, it seems that this is not possible at all, but may be there is a trick to do this?

      Delete
  6. Kai, sorry no. Changing the value of a managed property is the same as re-indexing that items property.

    ReplyDelete
  7. Hi Mikael.
    I have a question.
    If i have two managed properties say "A" and "B". And in the results my search phrase in some results is found in "A" and in some results is found in "B". Then i want to ensure that the results which contains search phrase in "A" should come first(should be boosted) than "B"

    Thanks

    ReplyDelete
    Replies
    1. You can try to add a managed property boost on A where you match on #. Or you can use FQL and xrank. Something like below where you query for "my query", but boost the items where the same query appears in A.

      xrank(string("my query", mode="simpleall"), A:string("my query", mode="simpleall"), boost=5000)

      Delete
    2. Hey Mikael Thanks a lot it worked !

      Delete