Unpredictable ordering results in the Edge GraphQL schema


Overview

The Headless Services module introduces a GraphQL endpoint for Sitecore Experience Edge. The endpoint allows querying content data from the Sitecore environment. The search query is used to search for content items and order the results by a specific field value.

For example:

{ 
  search(where:{ 
    AND:[{ 
      name:"_name", 
      value:"home" 
   }] 
 },  
  orderBy:{ 
    name:"title", 
    direction:ASC 
 }){ 
    results{ 
      name 
      path 
    } 
 } 
} 


When Solr indexes Sitecore items, tokenizers parse field contents into multiple tokens per field. Tokenized fields, such as OrderBy in the previous example, could make ordering unpredictable. The issue affects Sitecore Headless Services 18.0.0.

Scenario

Title is a default Sitecore XP field. It is defined in Solr configuration as a text field:

<fieldNames hint="raw:AddFieldByFieldName">
  <field fieldName="title" returnType="text" />
</fieldNames>


Text fields are mapped to dynamic Solr fields:

 <typeMatches hint="raw:AddTypeMatch">
    <typeMatch typeName="text" type="System.String" fieldNameFormat="{0}_t" cultureFormat="_{1}"  
     settingType="Sitecore.ContentSearch.SolrProvider.SolrSearchFieldConfiguration, Sitecore.ContentSearch.SolrProvider" />
</typematches>


Dynamic fields are defined in the Solr schema file and are mapped to the text_general field type (or a culture-specific equivalent):

<dynamicField name="*_t" type="text_general" indexed="true" stored="true"/>
<dynamicField name="*_t_en" type="text_general" indexed="true" stored="true"/>
<dynamicField name="*_t_da" type="text_da" indexed="true" stored="true"/>

The field type definition does not include docValues and uses StandardTokenizerFactory. Tokenizers split the input value into terms. The StandardTokenizerFactory usually produces multiple terms per field:

 <fieldType name="text_general" class="solr.TextField" positionIncrementGap="100" multiValued="false">
  <analyzer type="index">
    <tokenizer class="solr.StandardTokenizerFactory"/>
    <filter class="solr.StopFilterFactory" words="stopwords.txt" ignoreCase="true"/>
    <filter class="solr.LowerCaseFilterFactory"/>
  </analyzer>
  <analyzer type="query">
    <tokenizer class="solr.StandardTokenizerFactory"/>
    <filter class="solr.StopFilterFactory" words="stopwords.txt" ignoreCase="true"/>
    <filter class="solr.SynonymFilterFactory" expand="true" ignoreCase="true" synonyms="synonyms.txt"/>
    <filter class="solr.LowerCaseFilterFactory"/>
  </analyzer>
</fieldType>

 

Solution

To resolve the issue, consider the following options to create a non-tokenized field or modify Solr schema to include a copy field: