elasticsearch_search_api-1.0.x-dev/src/Search/ElasticSearchParamsBuilder.php

src/Search/ElasticSearchParamsBuilder.php
<?php

namespace Drupal\elasticsearch_search_api\Search;

use Drupal\elasticsearch_search_api\Search\Facet\Control\CompositeFacetControlInterface;
use Drupal\elasticsearch_search_api\Search\Facet\Control\FacetControlInterface;
use Drupal\elasticsearch_search_api\Search\Facet\FacetCollection;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\search_api\Entity\Index;
use Drupal\search_api\IndexInterface;

/**
 * Builds parameters to pass with an ElasticSearch search request.
 */
class ElasticSearchParamsBuilder {

  /**
   * Index id.
   *
   * @var \Drupal\search_api\Entity\Index
   */
  protected $index;

  /**
   * The lang code of the current language.
   *
   * @var string
   */
  protected $langcode;

  /**
   * Index factory adapter.
   *
   * @var \Drupal\elasticsearch_search_api\Search\IndexFactoryAdapter
   */
  protected $indexFactoryAdapter;

  /**
   * ElasticSearchParamsBuilder constructor.
   */
  public function __construct(IndexInterface $index, LanguageManagerInterface $languageManager, IndexFactoryAdapter $indexFactoryAdapter) {
    $this->index = $index;
    $this->langcode = $languageManager->getCurrentLanguage()->getId();
    $this->indexFactoryAdapter = $indexFactoryAdapter;
  }

  /**
   * Builds ElasticSearch parameters for the current search action.
   *
   * @param \Drupal\elasticsearch_search_api\Search\FacetedSearchActionInterface $searchAction
   *   The current search action to build the parameters for.
   *
   * @return array
   *   Parameters to pass to the ElasticSearch client.
   */
  public function build(FacetedSearchActionInterface $searchAction): array {
    $standard_filters = $this->getStandardFilters();

    if ($searchAction instanceof FacetedKeywordSearchAction && $keyword = $searchAction->getKeyword()) {
      $standard_filters[] = [
        [
          'function_score' => [
            'functions' => [
              [
                'filter' => [
                  'multi_match' => [
                    'query' => $keyword,
                    'fields' => [
                      'title^5',
                      'title.ngram',
                      'body^5',
                      'body.ngram',
                    ],
                  ],
                ],
                'weight' => 2,
              ],
            ],
            'score_mode' => 'multiply',
          ],
        ],
        [
          'bool' => [
            'should' => [
              'match' => [
                'custom_all' => $keyword,
              ],
            ],
          ],
        ],
      ];
    }

    $params = [
      'body' => [
        '_source' => FALSE,
        'from' => $searchAction->getFrom(),
        'size' => $searchAction->getSize(),
        'query' => [
          'bool' => [
            'must' => $standard_filters,
          ],
        ],
      ],
    ];

    $chosenFacetValues = $searchAction->getChosenFacetValues();

    if (count($searchAction->getAvailableFacets())) {
      $params['body']['aggs'] = $this->buildAggregations($searchAction, $chosenFacetValues);
    }

    if (!$chosenFacetValues->isEmpty()) {
      $post_filter = $this->buildFacetFilters($chosenFacetValues);
      $params['body']['post_filter'] = ['bool' => ['must' => $post_filter]];
    }

    $index = $this->getIndexName($this->index);
    $params['index'] = $index;

    return $params;
  }

  /**
   * Get standard filters for the search query.
   *
   * Returns a list of standard filters, such as language, published state,
   * and content type.
   *
   * @return array
   *   Standard filters.
   */
  protected function getStandardFilters() {
    return [
      [
        'term' => [
          'langcode' => $this->langcode,
        ],
      ],
      [
        'term' => [
          'status' => 1,
        ],
      ],
    ];
  }

  /**
   * Builds a filter for a given set of facet values.
   *
   * @param \Drupal\elasticsearch_search_api\Search\Facet\FacetCollection $facet_values
   *   Facet values.
   *
   * @return array
   *   Array to be used as an ElasticSearch filter.
   */
  protected function buildFacetFilters(FacetCollection $facet_values): array {
    $post_filter = [];
    /** @var \Drupal\elasticsearch_search_api\Search\Facet\FacetValueInterface[] $selected_values */
    foreach ($facet_values as $facet => $selected_values) {
      $facetControlService = \Drupal::service('elasticsearch_search_api.facet_control.' . $facet);
      if ($facetControlService instanceof CompositeFacetControlInterface) {
        $facet_post_filter = $facetControlService->buildFacetFilter($selected_values);
      }
      elseif ($facetControlService instanceof FacetControlInterface) {
        $facet_post_filter = [];
        foreach ($selected_values as $selected_value) {
          $facet_post_filter[] = [
            'term' => [
              $facetControlService->getFieldName() => $selected_value->value(),
            ],
          ];
        }
      }

      if (count($facet_post_filter) > 1) {
        $post_filter[] = [
          'bool' => [
            'should' => $facet_post_filter,
          ],
        ];
      }
      elseif (count($facet_post_filter) === 1) {
        $post_filter[] = reset($facet_post_filter);
      }
    }

    return $post_filter;
  }

  /**
   * Build aggregations for an elastic query.
   *
   * @param \Drupal\elasticsearch_search_api\Search\FacetedSearchActionInterface $searchAction
   *   The search action to get available facets from.
   * @param \Drupal\elasticsearch_search_api\Search\Facet\FacetCollection $chosenFacetValues
   *   Chosen facet values.
   *
   * @return array
   *   List of aggregations.
   */
  protected function buildAggregations(FacetedSearchActionInterface $searchAction, FacetCollection $chosenFacetValues) {
    $aggregations = [];

    foreach ($searchAction->getAvailableFacets() as $facet) {
      /** @var \Drupal\elasticsearch_search_api\Search\Facet\Control\FacetControlInterface $facetControlService */
      $facetControlService = \Drupal::service('elasticsearch_search_api.facet_control.' . $facet);
      if (!$facetControlService->addToAggregations()) {
        continue;
      }

      $aggregation_facet_values = $chosenFacetValues->without($facet);
      // Use a sub-aggregation & apply the the filter of all other facets on it.
      if (!$aggregation_facet_values->isEmpty()) {
        $agg_filter = $this->buildFacetFilters($aggregation_facet_values);

        $aggregations[$facet] = [
          'filter' => ['bool' => ['must' => $agg_filter]],
          'aggs' => [
            'filtered' => [
              'terms' => [
                'field' => $facetControlService->getFieldName(),
                'size' => 999,
              ],
            ],
          ],
        ];
      }
      else {
        $aggregations[$facet] = [
          'terms' => [
            'field' => $facetControlService->getFieldName(),
            'size' => 999,
          ],
        ];
      }
    }

    return $aggregations;
  }

  /**
   * Get the name of the index.
   *
   * @param \Drupal\search_api\Entity\Index $index
   *   The index.
   *
   * @return string
   *   The index name.
   */
  protected function getIndexName(Index $index) {
    return $this->indexFactoryAdapter->getIndexName($index);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc