Dataverse search is a powerful tool within Power Apps that helps users find the data they need quickly. By default, it leverages Azure AI Search capabilities, using both index and search analyzers to deliver relevant results. However, sometimes the default analyzers might not be sufficient, especially when dealing with special characters, unusual data formats, or specific linguistic requirements. This article delves into how you can tailor your search results by implementing custom column analyzers for Dataverse search, and how it enhances the precision and relevance of your search results.
Sometimes Dataverse Search doesn't return an exact match because the data in the searched column isn't easily understood, or because certain characters are automatically removed or ignored based on the default analyzer used by Dataverse Search service
Here are some examples where Dataverse search might not return the exact results you're looking for:
Desired | Actual |
---|---|
AB-84(q)(1)(c)orAB-84(1)(1)(-c) | Exact match Unwanted matches: Returns records with AB, (1), or (c) in a column resulting in multiple records that aren't relevant. |
2.2.3.1 | Exact match Unwanted matches: Returns records with 2.2, 2.3.1, .2 resulting in multiple records that aren't relevant |
PG-11.1 | Exact match Unwanted matches: Returns records with PG, -11, -11.1 resulting in multiple records that aren't relevant |
"%mn" +"ABC-123" | Exact match for: record has mnABC-123 Unwanted matches: record with mnhas a record with ABC-123 but doesn't include mn |
"Inspector of brakes" | Exact match Unwanted match: Inspector of boilers |
In such cases, custom analyzers can provide the necessary instructions to Dataverse Search to accurately match keywords and phrases with the expected data, ensuring more precise and relevant search outcomes.
Dataverse search relies on the robust Azure AI Search analyzers. So, understanding how these analyzers work is crucial for refining your search results. It's highly recommended to familiarize yourself with Analyzers for text processing in Azure AI Search to gain a deeper insight on managing searches.
By default, Dataverse search uses the Microsoft language analyzer based on the Dataverse organization's base language. If a specific Microsoft analyzer isn't available, it defaults to the Lucene Analyzer. These analyzers are automatically applied to all string or memo columns marked as searchable.
You can also use Built-in analyzers if the Azure AI Search built-in analyzers for a specific column works for you. You can also use available language analyzers, especially when dealing with data in languages different from your Dataverse base language.
To implement a built-in analyzer, create a row in the SearchAttributeSettings table, and set the Name, entityname, and attributename appropriately. Then configure the settings to point to a built-in search analyzer, like {"analyzer": "keyword"}
, or a language analyzer, such as { "analyzer": "it.microsoft"}
.
To apply a different analyzer for a Dataverse table column, you need to configure the SearchAttributeSettings table. By default, this table is empty.
Column | Description |
---|---|
Name | A descriptive name to help you identify the custom analyzer. |
entityname | The logical name of the table containing the column you want to configure. |
attributename | The logical name of the column for which the analyzer is used. |
settings | A JSON string that specifies your custom analyzer. For example: { "analyzer": "name_analyzer"} or {"indexanalyzer": "name_analyzer", "searchanalyzer": "name_analyzer"} . |
Important: The combination of entityname
and attributename
must be unique to avoid errors. To prevent unintentional duplication, consider adding an alternate key to the SearchAttributeSettings
table, specifying these two columns in the key by using Power Apps.
Alternatively, you can programmatically update the SearchAttributeSettings
table to avoid manual errors and ensure consistency.
The following C# code demonstrates how to create or replace a SearchAttributeSettings
record:
/// <summary>
/// Creates or replaces a SearchAttributeSettings record
/// </summary>
/// <param name="service">The authenticated IOrganizationService instance</param>
/// <param name="entityName">
/// The name of the entity for which the search attribute settings record is created.
/// </param>
/// <param name="attributeName">
/// The logical name of the column for which the search attribute settings record is created.
/// </param>
/// <param name="settings">The settings for the search attribute.</param>
/// <param name="overwriteExisting">Verify that the intent is to replace any existing record</param>
static void SetSearchAttributeSettings(IOrganizationService service, string entityName, string attributeName, string settings, bool overwriteExisting = false)
{
try
{
#region Check whether record exists
Entity existingRecord = null;
QueryExpression query = new("searchattributesettings")
{
ColumnSet = new ColumnSet(
"searchattributesettingsid",
"entityname",
"attributename",
"settings"),
Criteria = new FilterExpression(LogicalOperator.And)
{
Conditions = {
new ConditionExpression("entityname", ConditionOperator.Equal, entityName),
new ConditionExpression("attributename", ConditionOperator.Equal, attributeName)
}
}
};
// Retrieve any matching records
EntityCollection entityCollection = service.RetrieveMultiple(query);
if (entityCollection.Entities.Count > 1)
{
string message = "More than one record is found in searchattributesettings ";
message += $"with entityname {entityName} and attributename {attributeName}.";
throw new Exception(message);
}
if (entityCollection.Entities.Count == 1)
{
existingRecord = entityCollection.Entities[0];
}
#endregion Check whether record exists
if (existingRecord != null)
{
string currentSettings =