Using taxonomy fields in SharePoint 2010: Part III

By bhoeijmakers at January 13, 2011 21:21
Filed Under: .NET, SharePoint 2010

This is part III in my series about using TaxonomyFields in SharePoint 2010. In this part I will talk about how to search TaxonomyFields. I will show how to set up the metadata properties and how to search TaxonomyFields programmatically. This post continues on my previous posts about this subject:

 

Introduction

Part I: Declaration and initialization

Part II: Using taxonomyfields programmatically

Part III: Searching taxonomy fields (you are reading it!)

 

Managed Properties

To use our taxonomyfields in SharePoint search they need to be available in the managed properties of the farm. This works a little bit different with TaxonomyFields than with other fieldtypes. In this example I use the custom contenttype created in part I of this series and make the contained TaxonomyField “My taxonomy field” searchable using SharePoint search.

First I create a list named TaxonomyList and bind the custom contenttype “MyCustomContentType” to the list. The following image shows the list settings of the created list:

 

TaxListSettingsIII

 

Then I add a new item to the list and fill the TaxonomyField with a value. Don’t forget this step! This is necessary for the crawler to pick up the taxonomyfield. For SharePoint to create a crawled property, the field must contain a value when a full crawl is started.

 

TaxItemIII

 

When the item is added I start a full crawl. To do this go to Central Administration –> Manage Service Applications –> Enterprise Search Service Application. Then go to Content Sources and start a full crawl on the correct content source. I usually create a new content source containing only my demo-site so the crawl doesn’t take too long.

 

TaxCrawl

 

And now….we wait…

 

What happens now is that the crawler indexes the webapplication, including our new item containing the TaxonomyField. It then creates a Crawled Property for our TaxonomyField. A crawled property is created for all the fields containing a value within the crawled webapplication. The magic of it is that in case of TaxonomyFields a Managed Property is also automatically created which is mapped to the crawled property. These mapped taxonomyfields allways have the prefix owstaxId. The corresponding crawled properties have the prefiex ows_taxId_. We can see this in the “Metadata Properties” section of the Enterprise Search Service Application.

 

taxManagedProperty

 

The properties screen for this Managed Property looks like this:

 

taxManagedPropertySettings

 

Now we are finally ready to do some coding! In the next section I will create a webpart that uses code to find items using the custom taxonomy field.

 

NOTE: All of the above can be achieved using PowerShell, and you should use PowerShell to create managed and crawled properties when deploying real-life SharePoint solutions for customers as part of your deployment script. Check out this link for PowerShell cmdlets regarding Sharepoint Search: SP2010 PowerShell Commandlets on Technet

 

TIP: To test search queries there is a cool tool available from codeplex here: http://sharepointsearchserv.codeplex.com/

 

Searching a TaxonomyField from code

In this example I will create a very basic WebPart that gets data from a site using the search API. It will use the TaxonomyField I´ve created in this and the previous parts of this series in the WHERE clause of the search query. In this example I use the FullTextSqlQuery class to search the site.

 

To do this, first I add a visual webpart to my Visual Studio solution. In the .asx file I declare a basic DataView control to which I will databind my searchresults to make them visible on screen:

 

<asp:GridView ID="gvSearchResult" runat="server"></asp:GridView>

Then, in the codebehind I get the data from my site using the FullTextSqlQuery class and databind it to the grid:

 

Update 4th of November 2011: Be sure to read my follow-up post to learn how to improve this code to make it ready for a production environment!

 

 

        /// <summary>
        /// Binds the data to the grid
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Page_Load(object sender, EventArgs e)
        {
            gvSearchResult.DataSource = getData();
            gvSearchResult.DataBind();
        }
 
        /// <summary>
        /// Searches for items containing a Term
        /// </summary>
        /// <returns></returns>
        private DataTable getData()
        {
            DataTable dt = new DataTable();
 
            FullTextSqlQuery ftsq = new FullTextSqlQuery(SPContext.Current.Site);
            ftsq.QueryText = " SELECT Size, Rank, Path, Title, Description, Write FROM Scope() " +
                                string.Format("WHERE  ( (\"SCOPE\" = 'All Sites') ) AND " + 
                                "owstaxIdMyTaxonomyField = '#0{0}'  ORDER BY \"Rank\" DESC",
                                GetTermGuidByTitle("Investment Services"));
 
            ftsq.ResultTypes = ResultType.RelevantResults; 
 
            ResultTableCollection rtc = ftsq.Execute();
            if (rtc.Count > 0)
            {
                ResultTable relevantResults = rtc[ResultType.RelevantResults];
                dt.Load(relevantResults, LoadOption.OverwriteChanges);
            } 
 
            return dt;
        }
 
        /// <summary>
        /// Basic method to find a term. Of course this method needs improvement
        /// and is here for illustrational purposes only.
        /// DO NOT USE IN A PRODUCTION ENVIRONMENT
        /// </summary>
        /// <param name="title"></param>
        /// <returns></returns>
        private Guid GetTermGuidByTitle(string title)
        {
            // Open a taxonomysession and get the associated termstore from it
            TaxonomySession session = new TaxonomySession(SPContext.Current.Site);
            TermStore termStore = session.TermStores[0];
 
            Term term = termStore.GetTerms(title, true)[0];
 
            if (term != null)
                return term.Id;
            else throw new Exception("Term not found");
        }

 

You need to add a reference to the Microsoft.Office.Server.Search dll to make this code work.

 

In the code I am searching the Managed Property called owstaxIdMyTaxonomyField for the value

“Investment Services”. As you can see the query executed by the FullTextSqlQuery class looks as follows:

 

 ftsq.QueryText = " SELECT Size, Rank, Path, Title, Description, Write FROM Scope() " +
                  string.Format("WHERE  ( (\"SCOPE\" = 'All Sites') ) AND " + 
                  "owstaxIdMyTaxonomyField = '#0{0}'  ORDER BY \"Rank\" DESC",
                  GetTermGuidByTitle("Investment Services"));

 

The guid of the term I’m looking for is preceded by “#0”. This means that I want to search for the exact term. If you are searching for the term or any term below it in the termstore hierarchy prefix the guid with “#”.

 

NOTE: The GetTermGuidByTitle private method is just a quick way for me to get a term from the termstore. It is only printed here to show you a complete, working peace of code. If you want to look up a term from the termstore do it in a more robust way. In The 2nd part of this series I talk about how to programmatically lookup values from the termstore.

Comments (16) -

5/18/2011 11:33:02 PM #

You wrote "If you are searching for the term or any term below it in the termstore hierarchy prefix the guid with "#"." I saw the same on MSDN(msdn.microsoft.com/en-us/library/ff625182.aspx). However it seems that this doesn't works in FullTextSQLQuery. Have you tried this on your end using FullTextSQLQuery?

Thanks,
Prashant

Prashant United States | Reply

5/19/2011 7:42:18 AM #

Yes, I've tried and it works. What exactly is your problem?

Bart-Jan

bhoeijmakers Netherlands | Reply

5/19/2011 3:52:36 PM #

Lets say you have managed metadata term "Living Being"
Living Being(Term Id:1111...)

"Living Being" has child terms as follows:
Living Being -> Animal(Term Id:aaaa...)
Living Being -> Animal -> Dog(Term Id:bbbb...)
Living Being -> Animal -> Cat(Term Id:cccc...)

Now tag an item(field) with Cat. In the search try owstaxIdMyTaxonomyField='#aaaa...',i.e., search items tagged to "Animal" or any terms below it. You won't get any results back. Although clearly Cat is a descendant of Animal term.

Prashant United States | Reply

1/4/2012 11:20:30 AM #

Excellent post, thank you very much for teaching us these facts!

However, I also have problems with #guid. It will return only the items containing the term itself and not the ones containing the term's descendents as well, so it is the same as #0guid. I have tried with both FullTextSqlQuery and KeywordQuery and I get the same behaviour.

I thought that this might be due to the fact that the terms were not in the TaxonomyHiddenList, but adding them there did not change anything.

I give up the ghost, if you have any ideas regarding the matter I would be grateful to hear them.

Best Regards.

Ari Mastrokostas Greece | Reply

1/4/2012 12:40:28 PM #

Hi;

  Do not edit the TaxonomyHiddenList manually. This is handled by the eventhandlers that should be attached to your list containing custom taxonomyfields as I explain in the first post in this series.

If terms that are used to tag items within a sitecollection are not showing up in the taxonomyhiddenlist of that same sitecollection, something is wrong with your taxonomyfield/contenttype/list declaration.

bhoeijmakers Netherlands | Reply

10/25/2012 9:07:14 PM #

did you get any further with this, i have the same problem.

craigT United Kingdom | Reply

6/15/2011 3:52:47 PM #

Excellent post, you really saved me a lot of time with this post.
Thank you!

Jeroen Belgium | Reply

6/23/2011 8:03:24 PM #

Thanks a lot for the great post.

Question: in the query, you have scope of "All Sites". However, how do you search only the current site collection? Also a general question, what is the difference between specifying a search scope or no search scope specified at all?

I know that I could define a search scope for the current site collection, but there are many site collections, so defining a search scope per site collection may not be feasible.

Tony United States | Reply

6/24/2011 10:59:29 AM #

I'm afraid you'll have to define a searchscope for each site collection. You can do that if you are a sitecollection administrator via the Site Settings page. You could also create a feature with code behind that creates a searchscope for the current site collection. You can then activate that feature from within your webtemplate to automatically create a searchscope when the sitecollection is created.

bhoeijmakers Netherlands | Reply

6/24/2011 10:02:28 AM #

Make sure to approve the pages and/or publish a major version of the document(s) before starting the crawl.

If the document / page is not approved/published the crawler will not pickup the 'managed property'

My 2 cents... Wink

W0ut United States | Reply

6/24/2011 11:00:38 AM #

Yep, totally true. The Search crawl account has read rights on your sites, so it only crawls approved/published items.

bhoeijmakers | Reply

9/20/2012 11:43:14 AM #

Hi there, that's fantastic, a great help! Thank you! One question...

Let's suppose we're tagging the content multiple times and we want to find content which has tag matches - ordered by the more matches. I.e. Item A is tagged with "Monday", "Tuesday" and "Wednesday".... Item B tagged with "Tuesday" and "Monday"... Item C is tagged with just "Tuesday"... how can we order the results so that Item B quite rightly appears above Item C? At the moment we're just doing a WHERE Scope = scopenameasyou'vedoneabove AND CONTAINS(owsTaxIdNewsx0020Keywords, 'termguid OR termguid OR termguid'), but all the results are ranked the same and are not ordered based on the more hits... any suggestions of how to achieve this? If we discover how I'll definitely share it Smile

Thanks!

Ben Miller United Kingdom | Reply

10/23/2012 12:09:00 PM #

Great, was having hard time figuring out the format for owstaxIdMyTaxonomyField in my query and your post saved me some valuable minutes. Thank you!

Jussi Palo Finland | Reply

3/20/2013 12:49:11 PM #

I have an issue when querying owstaxIdMyTaxonomyField with FullTextSqlQuery

Baye France | Reply

3/20/2013 12:52:00 PM #

my error message is Property doesn't exist or is used in a manner inconsistent with schema settings

Baye France | Reply

3/20/2013 3:11:39 PM #

Baye,

  This is most probably caused because the managed property does not exist. Do you see the managed property in the Search Service Application?

regards,
Bart-Jan

bhoeijmakers | Reply

Pingbacks and trackbacks (2)+

Add comment




  Country flag
biuquote
  • Comment
  • Preview
Loading


About the author

Bart-Jan Hoeijmakers is Lead SharePoint Developer at VX Company. Since 2006 he is the driving force behind the development of several enterprise SharePoint projects within VX Company. He is a hardcore developer in both SharePoint and ASP.NET and loves to dive into the dark sides of SharePoint development.

Month List