|
|
2 weeks ago | |
|---|---|---|
| config | 2 weeks ago | |
| src/EventSubscriber | 2 weeks ago | |
| README.md | 2 weeks ago | |
| composer.json | 2 weeks ago | |
| solr_sort_ignore_articles.info.yml | 2 weeks ago | |
| solr_sort_ignore_articles.services.yml | 2 weeks ago | |
README.md
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_solr4.3 or later- Write access to the
confdirectory 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"