Skip to main content

Open Search

Configuration

# packages/headless.yaml
opendxp_headless:

opensearch:
hosts: # your index hosts
credentials: # your index credentials

API Search types

It is possible, to preconfigure specific search types:

# packages/headless.yaml
opendxp_headless:

# enable, if you want to have search types
api_search_types:
my_search_type: {}

my_extended_search_type:
additional_filter:
- special_filter # (additional filters, see Api Filter)
action_response:
response_class: 'App\Domain\Search\ResponseEntity\MyExtendedSearchResponse'

this will create the endpoints search/my-search-type and search/my-extended-search-type.

Search PHP API

This bundle provides a service to query an opensearch index.
Use the service HeadlessBundle\OpenSearch\Service\OpenSearchService to perform a search:

use OpenDxp\Bundle\HeadlessBundle\OpenSearch\Dto\OpenSearchDemand;
use OpenDxp\Bundle\HeadlessBundle\OpenSearch\Service\OpenSearchService;

class MySearchService {

public function __construct(protected OpenSearchService $openSearchService)
{}

public function mySearch()
{
$searchDemand = new OpenSearchDemand();
$searchDemand->setLocale('en');
$searchDemand->setOffset(0);
$searchDemand->setLimit(200);
$searchDemand->setOrder('id');
$searchDemand->setOrderDirection('desc');

$searchDemand->addConstraints([
'first_constraint': 'abc',
'second_constraint': 124
]);

// use a 'search type' of your choice
$result = $this->openSearchService->search('my_search_type', $searchDemand);

// do something with the result
$result->getHits();
$result->getTotalCount();
$result->getAggregations();

}
}

In order to modify the search, listen to the events provided:

class MySearchEventListener implements EventSubscriberInterface {

public function getSubscribedEvents(): array
{
return [
OpenSearchEvents::POST_BUILD_SORTS => ['onPostBuildSorts'],
OpenSearchEvents::POST_BUILD_QUERY => ['onPostBuildQuery', 10], // lower priority
OpenSearchEvents::POST_BUILD_POST_FILTER => ['onPostBuildPostFilter'],
OpenSearchEvents::POST_BUILD_AGGREGATIONS => ['onPostBuildAggregations']
OpenSearchEvents::PRE_SEARCH => ['onPreSearch']
];
}

public function onPreSearch(PreSearchEvent $event): void
{
// check for correct search type
if ($event->getSearchType() !== 'my_search_type') {
return;
}

// last change to modify the search demand, before the search will be performed
// example: change the index which will be queried
$searchDemand = $event->getSearchDemand();

$searchDemand->setIndex('my_other_index');
}

public function onPostBuildSorts(PostBuildSortsEvent $event): void
{
// check for correct search type
if ($event->getSearchType() !== 'my_search_type') {
return;
}
$sorts = $event->getSorts();

// modify existing sorts, or override with your own
$event->setSorts([new FieldSort('my_field', FieldSort::DESC)]);
}

public function onPostBuildQuery(PostBuildQueryEvent $event): void
{
// check for correct search type
if ($event->getSearchType() !== 'my_search_type') {
return;
}
$query = $event->getQuery();
$searchDemand = $event->getSearchDemand();

if (
$searchDemand->hasConstraint('first_constraint') &&
$searchDemand->getConstraint('first_constraint') == 'abc'
) {
// modify query based on your constraints
$query->add(new TermQuery('my_field', 'my_value'));
}
}

//...
}

This bundle works perfectly in conjunction with dynamic search bundle (open-dxp/dynamic-search-bundle) and the open search index provider bundle(open-dxp/dynamic-search-index-provider-opensearch-bundle).

Index mapping definition

To build document definitions for OpenDXP elements, extend from OpenDxp\Bundle\HeadlessBundle\DynamicSearch\Definition\Document\AbstractElementDefinition

Field Transformer

Generating element urls from cli is hard. Use the provided OpenDxp\Bundle\HeadlessBundle\ThirdParty\DynamicSearch\Transformer\Field\ElementPathExtractor to generate your element urls while indexing.

Example:

    $definition
->addSimpleDocumentFieldDefinition([
'name' => 'frontend_path',
'index_transformer' => [
'type' => 'explicit',
'configuration' => [
'type' => 'text',
'index' => false
]
],
'data_transformer' => [
'type' => ElementPathExtractor::class,
'configuration' => [
'arguments' => [
'locale' => $normalizerOptions['locale'] ?? null,
'site' => $this->getSite()
]
]
]
]);