How to query a term + children in SharePoint Search (KQL)?
In this article, I'll get back to basics of KQL in SharePoint Online's Search Service, and explain how to target a Managed Metadata term and its children.
Maybe everyone else just remembers how to do this straight off the bat, and how the service behaves in different scenarios... But I don't. And googling gave me a bunch of low confidence results. Which I had very low confidence in.
So here we are. I needed to try this out again, and document it for future reference.
Background
Table of Contents
- Background
- Problem
- Solution
- Step 1: Map Your Metadata Field to a Searchable Managed Property
- How to map CustomLocation to RefinableString02:
- Step 2: Craft Your KQL Query
- To target a term AND its child terms:
- To target ONLY the exact term (no children):
- Step 3: Test to make sure it works!
- PnP PowerShell:
- REST:
- Troubleshooting
- Summary
Table of Contents
- Background
- Problem
- Solution
- Step 1: Map Your Metadata Field to a Searchable Managed Property
- How to map CustomLocation to RefinableString02:
- Step 2: Craft Your KQL Query
- To target a term AND its child terms:
- To target ONLY the exact term (no children):
- Step 3: Test to make sure it works!
- PnP PowerShell:
- REST:
- Troubleshooting
- Summary
Okay - you (me) want to query SharePoint Online search and filter by a Managed Metadata term (and its adorable little child terms) using a custom taxonomy-type Site Column.
In my example, it's called CustomLocation
, but of course it can be whatever you want.
This is to enable scenarios like this:
- You have 15 offices in 2 countries: Finland and Sweden.
- Or if you're American, maybe you'll have Texas and California, because they're practically different countries.
- But due to the ongoing effect of the newly announced tariffs, we unfortunately can't afford to cover US scenarios anymore, so we'll talk about Finland and Sweden instead.
- You tag documents with the office location using the
CustomLocation
Managed Metadata field.- Good examples would be Helsinki, Pihtipudas and Eckerö for Finland, and Stockholm, Åpsala and Haparanda for Sweden.
- You are publishing SharePoint News articles, targeting the office location (using CustomLocation), to show your users relevant news, targeted to them (as they have their OfficeLocation field set on their user profile to match the value in CustomLocation).
- This works.
- But you also want to show all news targeted to Finland on your Finland intranet site, and all news targeted to Sweden on your Sweden intranet site.
- This was the trickier scenario.
And you want it to work. In production. Without sacrificing goats to the crawl gods.
Problem
I had no memory how this actually works, and if when googling I see some sites swearing on using a hash symbol, some say you need to use the label, some use a pipe, some don't use anything, some add numbers to the GUIDs, and some have long since given up on life and just use a text field instead of Managed Metadata.
So I decided to figure it out.
And since it took me a bit, I figured I'd share it here, too.
Solution
Let’s get to it, shall we?
This simple solution has just a couple of steps. The steps take about 5 minutes. Waiting for crawl to finish and your results to be updated can take anything from another 5 minutes to days. We're talking about SharePoint here, folks - adjust your expectations accordingly :)
Step 1: Map Your Metadata Field to a Searchable Managed Property
SharePoint Online doesn’t let you create new managed properties. You get a buffet of pre-created ones like RefinableString02
, and you have to map your stuff to them like it’s a game of metadata Tetris.
We used to only have a handful of these RefinableSomethingXX
properties, but Microsoft has been kind enough to add more over the years. You now have hundreds.
Good luck keeping track of what's used where.
Anyway. Onwards we go!
How to map CustomLocation
to RefinableString02
:
- Go to SharePoint Admin Center → More features → Search → Manage Search Schema.
- Find
RefinableString02
(or similar - just pick something that's not mapped yet, and make note of the name). - Click Edit.
- Under Mappings to crawled properties, add:
(That’s the crawled property for your Managed Metadata field namedows_taxId_CustomLocation
CustomLocation
.) - Optional: Rename the alias to something less soul-crushing like
CustomLocationTaxId
. If you're an OG you won't do this - you can deal with RefinableString02. - Save.
- Then wait.
- And wait.
- And maybe kick off a reindex on your list or library:
- Go to the list → Settings → Advanced settings → Reindex List
- Still no results? Check again tomorrow. Or go yell at The Cloud.
Step 2: Craft Your KQL Query
Now that CustomLocation
is mapped to RefinableString02
, you can query it using Keyword Query Language (KQL).
We should first figure out the term ID of the term we want to target. You can find this in the Term Store Management Tool, or by using PnP PowerShell.
Or, if you're crafty, you can inspect the value a news article or a page gets after it's crawled.
And that, of course, is what we're going to do.
The picture below is from Chrome SP Editor, a Chrome extension by my old friend Tomi Tavela, that lets you run KQL queries directly from your browser. SharePoint doesn't really come with a nice KQL interface, so you need to use some sort of tools to figure out the right queries.
I mean, you could always install the PnP Search web parts, or use PnP PowerShell, or just go full REST if you're into that. I'll share something about those later, too. But the extension is easier.
In the screenshot above, you can see the values in RefinableString02
for a news article tagged with "Åpsala", a definitely existent town in Sweden.
Let's break down what we see here:
- GP0|#
- Represents a specific term.
- This is the base identifier for a term in the taxonomy. It’s used to tag items directly with that term.
- L0|#
| - GTSet|#
- Represents the term set.
- This identifies the term set that the term belongs to. It’s useful for grouping or filtering terms within a specific taxonomy set.
- GPP|#
- Represents a parent term.
- This is used to indicate the parent of a term, especially in hierarchical taxonomies. Multiple GPP entries may appear to trace the lineage up to the root. Here #0d9f41cc-0bbe-4d5f-a675-a1d62e37122b is the parent term "Sweden".
Armed with this knowledge, we can now construct our KQL queries.
To target a term AND its child terms:
RefinableString02:<TermID>
Example:
RefinableString02:0d9f41cc-0bbe-4d5f-a675-a1d62e37122b
You can also add the #
symbol, like so many online sources tell you to do - but it doesn't seem to make a difference:
RefinableString02:#0d9f41cc-0bbe-4d5f-a675-a1d62e37122b
These should return the same results, as the property value in fact includes the parents (so if you've selected a child term on the page, the value to match against will include the parent term IDs - as well).
To target ONLY the exact term (no children):
You have a few options here - the simple solution is to check the exact value the column/property has, and add the label + Guid combo.
Something like below, in my case, to target only Sweden (and not its children Stockholm, Åpsala and Haparanda):
RefinableString02:Sweden|#0d9f41cc-0bbe-4d5f-a675-a1d62e37122b
You'd think it needs the hash before the GUID, but it seems to work both ways. I guess you can't search for a hash.
Or you can do this weird trick - add a zero in front of the GUID, and it seems to work. I guess it works as a shorthand for searching for the GP0
RefinableString02:00d9f41cc-0bbe-4d5f-a675-a1d62e37122b
You can, again, add the hash if you want to. It seems to work both ways.
Step 3: Test to make sure it works!
By now, you should have Chrome SP Editor installed, and you can use it to test your queries.
But if you don't, here are some other ways to test your KQL queries.
PnP PowerShell:
Connect-PnPOnline -Url "https://yourtenant.sharepoint.com/sites/yoursite" -Interactive
$query = 'RefinableString02:#0d9f41cc-0bbe-4d5f-a675-a1d62e37122b'
$results = Submit-PnPSearchQuery -Query $query -All
$results.PrimarySearchResults | Format-Table Title, Path
REST:
GET https://yourtenant.sharepoint.com/sites/yoursite/_api/search/query?querytext=%27RefinableString02:"0d9f41cc-0bbe-4d5f-a675-a1d62e37122b"%27
Authorization: Bearer <access_token>
(Or just open it in a browser if you're already logged in)
Troubleshooting
A couple of easy tips:
- No results? Did you reindex the list? Did you wait for crawl? Are you 100% sure the mapping is correct? Do you at least get SOME results back?
- Still no results? Try lowercase term IDs. Try searching for the label, or label|GUID format. Wait some more.
- Still still no results? Try mapping to a different RefinableString. Maybe
RefinableString03
isn't as broken asRefinableString02
. - Still still still no results? Leave a comment in the comments-section below!
Summary
A super quick wrap-up of the key points.
Use SharePoint Term Store to figure out the exact term id, and use Chrome SP Editor or similar to test your queries.
And here's what you (could) set up:
Thing | Value |
---|---|
Metadata Field | CustomLocation |
Crawled Property | ows_taxId_CustomLocation |
Managed Property | RefinableString02 |
Term Query (with children) | RefinableString02:#<TermID> |
Term Query (exact only) | RefinableString02:0<TermID>" |
Comments
No comments yet.