logo
logo

Configuration

The Search API applies a default search configuration to all searches it executes, e.g. allows meaningful defaults for the properties to load, or default filters.

Filters can be defined by configuration (using settings) or via code using the query contributor framework.

Default Search configuration via settings

This default search configuration is retrieved from a setting in M. In this section of the documentation we will take a closer look at this setting, referred to as 'SearchDefaults'. The setting's name is variable. It is passed into the search related API resources as a parameter (called "name"). When a UI components performs a REST call, it will lookup the setting in its configuration and pass it to the Search controller.

A good example from Sitecore Content Hub is SearchConfiguration.json. The setting's category is "PortalConfiguration".

The search setting's schema has the following properties:

  • Name: The name of the setting
  • Take: The number of results to return by default. This value is only used when the search page doesn't have paging.
  • Filters: The filters to append to each query. The filters are combined with AND. (see Filters section)
  • Facets: The definitions used as facets. The schema determines how facets are linked to result-entities (using taxonomy relations, ...). (See facets section)
  • Followups: Followup facet configuration. If a facet filter is applied for a certain definition we will also append other facets in the search query.
  • PropertiesToLoad: The properties that are included in the results.
  • relationsToLoad: The relation that are included in the results
  • renditionsToLoad: The rendition names to load in the results, for entities having renditions.
  • ResultTypes: The types of entities that are returned as results. Filters are added to the search-query to make sure only entities of these types are returned.
  • SuperFacets: If a certain definition is flagged as a superfacet in configuration the search response will contain additional information about the selected superfacet.
  • Sorting: Default sorting

Example

{
    "name": "SearchConfiguration",
    "take": 10,
    "filters": [
        {
            "name": "relations.FinalLifeCycleStatusToAsset.parents",
            "operator": "Equals",
            "valueExpression": "String(\"StatusValue\") == \"Approved\""
        }
    ],
    "facets": [
        {
            "name": "M.Campaign"
        },        
        {
            "name": "M.AssetOriginator",
            "limit": 3,
            "sorting": "Alphabetical",
            "direction": "Ascending"
        }
    ],
    "followups": [        
        {
            "name": "M.AssetType",
            "valueExpression": "string(\"ClassificationName\") == \"Video\"",
            "followupName": "Ms.BitRate"
        }
    ],
    "superfacets": [
        {
            "definition": "M.Brand"
        }
    ],
    "propertiesToLoad": [
        "FileName",
        "Renditions"
    ],
    "resultTypes": [
        "M.Asset"
    ],
    "sorting": [
        {
            "property": "ModifiedOn",
            "direction": "Descending"
        }
    ]
}

Facets

The most simple example of defining a facet is by using the definition name. Please note that facets entirely depend on the Sitecore Content Hub schema. (ex. definitions being marked as IsTaxonomyItemDefinition.

We support 2 types of facets:

  • Normal facets (relations)
  • Field facets (properties)

Normal facet

{
    "name": "M.Campaign"
}

Field facet

{
    "name": "FileExtension",
    "type": 1
}

Each facet can be configured to only return a limited number of facet values using the optional limit parameter. The default number of returned facet values is 10. Setting the limit parameter to 0 means it will return all facet values.

The optional sorting & direction parameter configure the sorting options for the current facet.

Available facet sorting options are:

  • Count (default)
  • Alphabetical
  • Field

Please note that alphabetical sorting is only usefull when all facet values are returned.

Default Filters via Json Configuration Settings

Filters can be defined by configuration (using this setting) or via code using the query contributor framework.

The filters section of the setting only allows AND filters. Each value expression used in the filter should resolve to a single Id.

If the filter expression can not be resolved an exception is thrown.

Example:

{
    "name": "relations.FinalLifeCycleStatusToAsset.parents",
    "operator": "Equals",
    "valueExpression": "String(\"StatusValue\") == \"Approved\""
}

The example above applies a filter on the Id of Lifecycle status approved. (single Id).

If no value expression is used we will assume that the name is a definition name and we will apply a definition filter.

{
    "name": "M.Asset"
}

The example above applies a filter on definition_name == "M.Asset".

It is also possible to create a filter of filters. There, you can also choose which operator to apply for those inner filters.

Here is an example:

{
    "operator": "OR",
    "filters": [
        {
            "name": "relations.FinalLifeCycleStatusToAsset.parents",
            "operator": "Equals",
            "valueExpression": "String(\"StatusValue\") == \"Created\""
        },
        {
            "name": "relations.FinalLifeCycleStatusToAsset.parents",
            "operator": "Equals",
            "valueExpression": "String(\"StatusValue\") == \"Rejected\""
        }
    ]
}

Default Filters via Code

Another option to append filters is via code.

The example below applies an OR filter on multiple definition names and a specific one for M.Asset (lifecycle status approved).

The filter looks like this:

(definition = "M.Sku" OR definition = "M.Product" OR definition = "M.Campaign" OR definition = "M.Recipe" OR (definition = M.Asset AND LifeCycleStatus = Approved))

public class SearchConfigurationQueryContributor : IQueryContributor
    {
        private readonly IQuerying _querying;

        public SearchConfigurationQueryContributor(IQuerying querying)
        {
            this._querying = querying;
        }

        public Base.Search.Filters.FilterBase AddQuery(QueryContext context)
        {
            CompositeFilter filter = new CompositeFilter(FilterCombineMethod.Or);

            var qb = new QueryBuilder();

            //First step is to resolve final lifecycle status = Approved. (we are only gonna show approved stuff in the search.)
            long? approvedId = this._querying.Basic.Entities.SingleId(qb.Definition.Name == Stylelabs.M.Content.Constants.FinalLifeCycleStatusDefinition.DefinitionName &&
                qb.String(Stylelabs.M.Content.Constants.FinalLifeCycleStatusDefinition.StatusValue) == Stylelabs.M.Content.Constants.FinalLifeCycleStatusDefinition.ApprovedStatus);

            if (!approvedId.HasValue)
                throw new InvalidOperationException("Could not resolve approved status.");

            //These are the definitions we will apply a simple filter for (OR between definitions)
            string[] definitionsToDisplay = new string[] { "M.Sku", "M.Product", "M.Campaign", "M.Recipe" };
            foreach(string definition in definitionsToDisplay)
            {
                filter.Add(new FieldFilter<string>(Stylelabs.M.Base.ElasticSearch.Constants.PropertyNames.DefinitionName) { Value = definition });
            }

            //For asset we will only display the approved ones
            var assetFilter = new CompositeFilter(FilterCombineMethod.And);
            assetFilter.Add(new FieldFilter<string>(Stylelabs.M.Base.ElasticSearch.Constants.PropertyNames.DefinitionName) { Value = "M.Asset" });
            assetFilter.Add(new FieldFilter<long>("relations.FinalLifeCycleStatusToAsset.parents") { Value = approvedId.Value });
            filter.Add(assetFilter);

            return filter;
        }
    }

This querycontributer allows you to directly influence the filters being applied on the query. These filters will not be visible on the client-side. (ex querystring, querybuilder etc.)

Once the querycontributer class is ready the next step is to register it in your project's ApplicationModule

public override void OnConfiguration(IContainer container)
        {
            base.OnConfiguration(container);

            IQueryConfiguration queryConfiguration = container.Resolve<IQueryConfiguration>();
            queryConfiguration.QueryContributorRegistry.Add<SearchConfigurationQueryContributor>("SearchConfiguration");
        }

You can combine multiple query contributers together with the filters from configuration. A query contributer is always tied to the name of the SearchConfiguration it should append the filters for.

Can we improve this article ? Provide feedback