Enable sorting on terms minus leading symbols or articles.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6.0 KiB

Solr sort: ignore leading articles

Adds the string_sort_ignore_articles Solr field type and uses it for the Search API sort field(s) listed in solr_sort_ignore_articles.settings, so "The Matrix" sorts under M and "!Introduction" sorts under I.

Requirements

  • Drupal 10 or 11
  • search_api_solr 4.3 or later
  • Write access to the conf directory of the Solr core, and the ability to reload the core

How it works

search_api_solr never sorts on the field you index. For every string and fulltext field it copies the first value into a companion field named sort_;<langcode>_<field id> (encoded as sort_X3b_en_title), and sorting resolves to that field. Those companion fields are matched by the dynamic field sort_X3b_<langcode>_*, which is typed as the language's ICU collation — one collation per language, with no per-field override.

This module subscribes to PostConfigFilesGenerationEvent and appends an explicit <field> for the fields you name to schema_extra_fields.xml, plus the field type to schema_extra_types.xml. In Solr an explicit field always wins over a matching dynamicField, so only the named fields get the new analysis and every other sort keeps the default collation.

The module never talks to Solr itself. It only changes what search-api-solr:get-server-config generates — deploying that to the core is a manual step.

Deployment

1. Install and enable

composer require roblib/solr_sort_ignore_articles
drush en solr_sort_ignore_articles

2. Add a sort field to the index

At /admin/config/search/search-api/index/<index>/fields, add Content » Title a second time, change its machine name to title_sort and set its type to String. In config it looks like this:

# search_api.index.<index>.yml, under field_settings:
title_sort:
  label: 'Title (sort, ignore articles)'
  datasource_id: 'entity:node'
  property_path: title
  type: string
  dependencies:
    module:
      - node

Using a separate field keeps sorting on the existing title field unchanged. To change title itself instead, put title in solr_sort_ignore_articles.settings:fields and skip this step.

The module ships with title_sort as the default. To override:

drush config:set solr_sort_ignore_articles.settings fields.0 title_sort
drush config:set solr_sort_ignore_articles.settings fields.1 field_alt_title

Export config, and remember that any later change here means repeating steps 3 and 4.

3. Update the Solr schema

Generate the config set, matching the Solr version actually running on the target server:

drush search-api-solr:get-server-config <server> /tmp/solr_config.zip <solr-version>

Sanity check the two generated files before deploying:

unzip -p /tmp/solr_config.zip schema_extra_types.xml  | grep -A3 string_sort_ignore_articles
unzip -p /tmp/solr_config.zip schema_extra_fields.xml | grep 'sort_X3b_.*_title_sort'

Then deploy to the core's conf directory by one of two routes.

Full replacement — only when the core belongs to this site alone and the config set was generated for the same Solr version the server runs:

unzip -o /tmp/solr_config.zip -d /path/to/solr/server/solr/<core>/conf

**Hand-append ** — required when the core is shared with other Drupal sites, or when the target runs a different Solr major version than the config set was generated for. A full replacement would discard other sites' additions, and a config set for the wrong Solr version brings an incompatible solrconfig.xml along with it.

Append the module's block to the end of each of the two files in the core's conf directory. Both files are bare XML fragments with no root element, and field types do not have to precede the fields that use them.

schema_extra_types.xml:

<!-- solr_sort_ignore_articles -->
<fieldType name="string_sort_ignore_articles" class="solr.TextField" sortMissingLast="true" omitNorms="true">
  <analyzer>
    <tokenizer class="solr.KeywordTokenizerFactory"/>
    <filter class="solr.PatternReplaceFilterFactory" pattern="^[^\p{L}\p{N}]+" replacement="" replace="all"/>
    <filter class="solr.PatternReplaceFilterFactory" pattern="^(?i)(a\s+|an\s+|the\s+)" replacement="" replace="all"/>
    <filter class="solr.PatternReplaceFilterFactory" pattern="^[^\p{L}\p{N}]+" replacement="" replace="all"/>
    <filter class="solr.LowerCaseFilterFactory"/>
    <filter class="solr.TrimFilterFactory"/>
  </analyzer>
</fieldType>

schema_extra_fields.xml, one line per language, copied from the generated zip:

<!-- solr_sort_ignore_articles: these win over the matching sort_X3b_LANG_* dynamic fields -->
<field name="sort_X3b_en_title_sort" type="string_sort_ignore_articles" indexed="true" stored="false" multiValued="false"/>
<field name="sort_X3b_und_title_sort" type="string_sort_ignore_articles" indexed="true" stored="false" multiValued="false"/>
<field name="sort_X3b_zxx_title_sort" type="string_sort_ignore_articles" indexed="true" stored="false" multiValued="false"/>

Keep the comment markers — they are what makes the block findable and cleanly removable later.

Both blocks load unchanged on Solr 8.11 and 9.x.

Reload the core:

curl -sS "http://<solr-host>:8983/solr/admin/cores?action=RELOAD&core=<core>"

A malformed fragment fails the reload with a schema parse error and the core keeps its previous schema, so this is safe to retry.

4. Reindex

The sort field is only populated at index time, so existing documents keep their old values until reindexed:

drush search-api:reset-tracker && drush search-api:index

5. Add the sort criterion

In Views, add the new sort criterion (Title (sort, ignore articles)) to the search view.

Verifying

At /solr/#/<core>/analysis, field type string_sort_ignore_articles with input The !Matrix should produce the single token matrix.

The field itself can be confirmed with the Schema API:

curl -sS "http://<solr-host>:8983/solr/<core>/schema/fields/sort_X3b_en_title_sort"