How to combine 2 entity fields in Search API (single valued)

Created on 7 December 2016, almost 8 years ago
Updated 5 May 2024, 4 months ago

How can I combine two entity fields (for example DCAT and Node) into one Search API field to apply a facet on it.

Currently I wrote a custom SearchApiProcessor based on the AddUrl class from SearchAPI. But it seems that the indexation is done as a multiple values field automatically. What do I need to do to make this single valued so multiple values handling isn't active in Views.


namespace Drupal\odp_search\Plugin\search_api\processor;

use Drupal\search_api\Datasource\DatasourceInterface;
use Drupal\search_api\Item\ItemInterface;
use Drupal\search_api\Processor\ProcessorPluginBase;
use Drupal\search_api\Processor\ProcessorProperty;

/**
 * Adds the content and dcat title to the indexed data.
 *
 * @SearchApiProcessor(
 *   id = "field_title",
 *   label = @Translation("Title field"),
 *   description = @Translation("Adds the item's title to the indexed data."),
 *   stages = {
 *     "add_properties" = 0,
 *   },
 *   locked = true,
 *   hidden = true,
 * )
 */
class FieldTitle extends ProcessorPluginBase {

  /**
   * {@inheritdoc}
   */
  public function getPropertyDefinitions(DatasourceInterface $datasource = NULL) {
    $properties = array();

    if (!$datasource) {
      $definition = array(
        'label' => $this->t('Combined title'),
        'description' => $this->t('Combined title field for ODP content and DCAT datasets.'),
        'type' => 'text',
        'processor_id' => $this->getPluginId(),
      );
      $properties['odp_search_title'] = new ProcessorProperty($definition);
    }

    return $properties;
  }

  /**
   * {@inheritdoc}
   */
  public function addFieldValues(ItemInterface $item) {
    $entity = $item->getOriginalObject()->getValue();

    $title = NULL;
    if ($entity->getEntityType()->id() == 'dcat_dataset') {
      $title = $entity->get('name');
    }
    else if ($entity->getEntityType()->id() == 'node') {
      $title = $entity->get('title');
    }

    if ($title) {
      $fields = $this->getFieldsHelper()
        ->filterForPropertyPath($item->getFields(), NULL, 'odp_search_title');
      foreach ($fields as $field) {
        if (!$field->getDatasourceId()) {
          $field->addValue($title->getString());
        }
      }
    }
  }

}

Any suggestions?

PS: I'm trying to index it into SOLR.

📌 Task
Status

Postponed: needs info

Version

1.0

Component

Documentation

Created by

🇧🇪Belgium Jeroen_005

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇦🇷Argentina drupal-son

    Hi,

    I would like to combine location fields who have latitude / longitude fields on it to be able to filter by distance.
    I can make it work for 1 single field, I just drill down till the coordinates latlon pairs and configure the field type to latitude/longitude.

    But now I have a main content type with 3 entity reference fields to a location content type.
    The location content type contains the geofield.

    I want to combine the 3 and filter by location (distance) on the 3 at a time.

    I tried creating a Processor Plugin but wasn't able to accomplish what I needed.
    I tried the Union aggregation but that aggregates the whole referenced entity.
    I need to drill down to the coordinates latlon on the combined as an indexed field I can use on my index.
    Is there a way to drill down on an aggregated field?

    What is the best wat to do this?

    Thanks.

  • 🇦🇹Austria drunken monkey Vienna, Austria

    Seems like the “Aggregated field” provided by Search API would already mostly cover that use case, except that the UI currently doesn’t allow you to specify nested properties as the source of the aggregation (as you say, you can only aggregate the whole entities) – see Allow adding indirect fields/properties in aggregate_fields processor Active . However, you can already get this to work correctly by directly editing the search index’s config (see, e.g., comment #20 in the linked issue for an example). Adding support in the UI for this is, unfortunately, not that simple.

  • 🇦🇷Argentina drupal-son

    @drunken-monkey that is an interesting approach ...

    I tried it and this was the result:
    - I created an aggregated field with my 3 location fields.
    - I exported the configuration and changed by hand the 3 fields to point to the nested geofield and nested lat/lon value (just like I see when drilling down a single location field).
    - I imported the configuration.
    - I reindexed again and cleared caches.
    - I tested my query using the search_api_location filter aggregated field value.
    - Always get no results no matter how big radius I use.

    This is how the aggregated field looks like after manual tweaking:

      field_locations_union:
        label: 'Locations Union'
        property_path: aggregated_field
        type: location
        configuration:
          type: union
          fields:
            - 'entity:node/field_common_locations:field_ph_coordinates:latlon'
            - 'entity:node/field_en_locations:field_ph_coordinates:latlon'
            - 'entity:node/field_ph_locations:field_ph_coordinates:latlon'

    This is how the search api query location filter looks like:

          $location_options[] = [
            'field' => 'field_locations_union',
            'lat' => $geocoding['lat'],
            'lon' => $geocoding['lon'],
            'radius' => $geocoding['radius'],
          ];
    
          $query->setOption('search_api_location', $location_options);

    I was curious how the UI will behave after reimporting the manual tweaked configuration ... It looked like if no fields were selected to be combined. However if I exported the configuration again, the manual changes remain the same, so they are not destroyed on subsequent config exports.

    Any other hint or idea?

  • Status changed to Postponed: needs info 4 months ago
  • 🇦🇹Austria drunken monkey Vienna, Austria

    At a glance, this looks like it should have worked.

    After reindexing, can you look into the indexed contents of your Solr server and check whether the field_locations_union field (probably locm_field_locations_union in Solr) is present, and the contents look as expected?
    Then you could try to look at the Solr request generated for your search query (using, e.g., the Solr Devel module) and see whether that contains the appropriate filter parameters.

Production build 0.71.5 2024