I want to alter the search API Solr query in Drupal 8 to order by field null in hook_search_api_solr_query_alter(). How do I add my sort expression in the Solr search query? Do I need to add it in hook_views_query_alter()?
2 Answers
I also had this issue, I couldn't find an easy way to sort by null in a query alter (although Solr does have sortMissingLast, I just couldn't figure out how to inject it through Search API). Instead, I added a processor to check the field in question and add another field to identify whether it's there or not. Then you can sort by that.
<?php namespace Drupal\my_module\Plugin\search_api\processor; use Drupal\Core\Annotation\Translation; use Drupal\search_api\Annotation\SearchApiProcessor; use Drupal\search_api\Datasource\DatasourceInterface; use Drupal\search_api\Item\ItemInterface; use Drupal\search_api\Processor\ProcessorPluginBase; use Drupal\search_api\Processor\ProcessorProperty; /** * Checks for my field. * * @SearchApiProcessor( * id = "my_field_null", * label = @Translation("Has My Field"), * description = @Translation("Adds a check for null field to index."), * stages = { * "add_properties" = 0, * }, * locked = true, * hidden = false, * ) */ class MyFieldNull extends ProcessorPluginBase { /** * Machine name of the processor. * @var string */ protected $processor_id = 'my_field_null'; /** * {@inheritdoc} */ public function getPropertyDefinitions(DatasourceInterface $datasource = NULL) { $properties = []; if (!$datasource) { $definition = [ 'label' => $this->t('Has My Field'), 'description' => $this->t('Does this have my field?'), 'type' => 'string', 'processor_id' => $this->getPluginId(), ]; $properties[$this->processor_id] = new ProcessorProperty($definition); } return $properties; } /** * {@inheritdoc} */ public function addFieldValues(ItemInterface $item) { $entity = $item->getOriginalObject()->getValue(); if (method_exists($entity, 'hasField') && $entity->hasField('field_my_field')) { $has_field = TRUE; } else { $has_field = FALSE; } $fields = $this->getFieldsHelper() ->filterForPropertyPath($item->getFields(), NULL, $this->processor_id); foreach ($fields as $field) { $field->addValue($has_field); } } } I found an answer that works without writing any Drupal hooks or altering any PHP code!
Thanks to @ognockocaten for pointing out the sortMissingLast option! Looking at https://solr.apache.org/guide/6_6/field-type-definitions-and-properties.html pointed me to altering the schema.xml file for solr.
The doc is for solr 6.6, but it also works for Solr 7.
All you have to do is add the sortMissingLast=true to your fieldType and restart solr
I wanted my date field to have the nulls at the bottom, so I ended up changing the pdate fieldType.
<fieldType name="pdate" class="solr.DatePointField" docValues="true" sortMissingLast="true"/> After restarting solr, your null results will be at the bottom! Woohoo!