Skip to content

Commit

Permalink
NEXT-34030 - ES exact hit
Browse files Browse the repository at this point in the history
  • Loading branch information
OliverSkroblin committed Apr 5, 2024
1 parent c45e72f commit 6863c96
Show file tree
Hide file tree
Showing 13 changed files with 214 additions and 7 deletions.
7 changes: 7 additions & 0 deletions src/Core/Content/Test/Product/ProductBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,13 @@ public function __construct(
$this->tax($taxKey);
}

public function number(string $number): self
{
$this->productNumber = $number;

return $this;
}

/**
* @return array<mixed>
*/
Expand Down
2 changes: 2 additions & 0 deletions src/Elasticsearch/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->children()
->scalarNode('timeout')->end()
->integerNode('term_max_length')->end()
->scalarNode('search_type')->end()
->end()
->end()
->arrayNode('administration')
Expand All @@ -62,6 +63,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->children()
->scalarNode('timeout')->end()
->integerNode('term_max_length')->end()
->scalarNode('search_type')->end()
->end()
->end()
->end()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public function __construct(
private readonly EntityAggregatorInterface $decorated,
private readonly AbstractElasticsearchAggregationHydrator $hydrator,
private readonly EventDispatcherInterface $eventDispatcher,
private readonly string $timeout = '5s'
private readonly string $timeout,
private readonly string $searchType
) {
}

Expand All @@ -52,6 +53,7 @@ public function aggregate(EntityDefinition $definition, Criteria $criteria, Cont
$result = $this->client->search([
'index' => $this->helper->getIndexName($definition),
'body' => $searchArray,
'search_type' => $this->searchType,
]);

$result = $this->hydrator->hydrate($definition, $criteria, $context, $result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public function __construct(
private readonly CriteriaParser $criteriaParser,
private readonly AbstractElasticsearchSearchHydrator $hydrator,
private readonly EventDispatcherInterface $eventDispatcher,
private readonly string $timeout = '5s'
private readonly string $timeout,
private readonly string $searchType
) {
}

Expand Down Expand Up @@ -68,6 +69,7 @@ public function search(EntityDefinition $definition, Criteria $criteria, Context
'index' => $this->helper->getIndexName($definition),
'track_total_hits' => true,
'body' => $search,
'search_type' => $this->searchType,
]);

$result = $this->hydrator->hydrate($definition, $criteria, $context, $result);
Expand Down
4 changes: 4 additions & 0 deletions src/Elasticsearch/Product/ProductSearchQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ public function build(Criteria $criteria, Context $context): BoolQuery

$tokens = $this->tokenizer->tokenize((string) $criteria->getTerm());
$tokens = $this->tokenFilter->filter($tokens, $context);
$term = strtolower((string) $criteria->getTerm());
if (!\in_array($term, $tokens, true)) {
$tokens[] = $term;
}

foreach ($tokens as $originalToken) {
$tokenBool = new BoolQuery();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ elasticsearch:
search:
timeout: 5s
term_max_length: 300
search_type: "query_then_fetch"
administration:
hosts: "%env(string:ADMIN_OPENSEARCH_URL)%"
enabled: "%env(bool:SHOPWARE_ADMIN_ES_ENABLED)%"
Expand All @@ -16,6 +17,7 @@ elasticsearch:
search:
timeout: 5s
term_max_length: 300
search_type: "query_then_fetch"
index_settings:
number_of_shards: 3
number_of_replicas: 3
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
elasticsearch:
index_settings:
number_of_shards: 1
number_of_replicas: 0

2 changes: 2 additions & 0 deletions src/Elasticsearch/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@
<argument type="service" id="Shopware\Elasticsearch\Framework\DataAbstractionLayer\AbstractElasticsearchSearchHydrator"/>
<argument type="service" id="event_dispatcher"/>
<argument>%elasticsearch.search.timeout%</argument>
<argument>%elasticsearch.search.search_type%</argument>
</service>

<service id="Shopware\Elasticsearch\Framework\DataAbstractionLayer\ElasticsearchEntityAggregator"
Expand All @@ -172,6 +173,7 @@
<argument type="service" id="Shopware\Elasticsearch\Framework\DataAbstractionLayer\AbstractElasticsearchAggregationHydrator"/>
<argument type="service" id="event_dispatcher"/>
<argument>%elasticsearch.search.timeout%</argument>
<argument>%elasticsearch.search.search_type%</argument>
</service>

<service id="Shopware\Elasticsearch\Product\SearchKeywordReplacement"
Expand Down
8 changes: 6 additions & 2 deletions src/Elasticsearch/Test/ElasticsearchTestTestBehaviour.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ protected function createEntityAggregator(): ElasticsearchEntityAggregator
$this->getDiContainer()->get(Client::class),
$decorated,
$this->getDiContainer()->get(AbstractElasticsearchAggregationHydrator::class),
$this->getDiContainer()->get('event_dispatcher')
$this->getDiContainer()->get('event_dispatcher'),
'5s',
'dfs_query_then_fetch'
);
}

Expand All @@ -89,7 +91,9 @@ protected function createEntitySearcher(): ElasticsearchEntitySearcher
$this->getDiContainer()->get(ElasticsearchHelper::class),
$this->getDiContainer()->get(CriteriaParser::class),
$this->getDiContainer()->get(AbstractElasticsearchSearchHydrator::class),
$this->getDiContainer()->get('event_dispatcher')
$this->getDiContainer()->get('event_dispatcher'),
'5s',
'dfs_query_then_fetch'
);
}

Expand Down
109 changes: 109 additions & 0 deletions tests/integration/Elasticsearch/Product/SearchCasesTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php declare(strict_types=1);

namespace Shopware\Tests\Integration\Elasticsearch\Product;

use Doctrine\DBAL\Connection;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Shopware\Core\Content\Product\ProductDefinition;
use Shopware\Core\Content\Test\Product\ProductBuilder;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Test\IdsCollection;
use Shopware\Core\Framework\Test\TestCaseBase\DatabaseTransactionBehaviour;
use Shopware\Core\Framework\Test\TestCaseBase\KernelTestBehaviour;
use Shopware\Elasticsearch\Framework\DataAbstractionLayer\ElasticsearchEntitySearcher;
use Shopware\Elasticsearch\Test\ElasticsearchTestTestBehaviour;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* @internal
*/
#[CoversClass(ElasticsearchEntitySearcher::class)]
class SearchCasesTest extends TestCase
{
use DatabaseTransactionBehaviour;
use ElasticsearchTestTestBehaviour;
use KernelTestBehaviour;

private static IdsCollection $ids;

/**
* @param array<mixed> $products
*/
#[DataProvider('numbersProvider')]
public function testSearch(array $products, string $term, string $best): void
{
$this->clearElasticsearch();

$this->getContainer()->get(Connection::class)->executeStatement('DELETE FROM product');

$this->getContainer()->get('product.repository')->create(array_values($products), Context::createDefaultContext());

$this->indexElasticSearch();

$searcher = $this->createEntitySearcher();

$criteria = new Criteria();
$criteria->addState(Criteria::STATE_ELASTICSEARCH_AWARE);
$criteria->setTerm($term);

$definition = $this->getContainer()->get(ProductDefinition::class);

$result = $searcher->search($definition, $criteria, Context::createDefaultContext());

$scores = [];
foreach ($result->getData() as $item) {
$scores[self::$ids->getKey((string) $item['id'])] = $item['_score'];
}

static::assertEquals(
$best,
self::$ids->getKey((string) $result->firstId()),
print_r($scores, true)
);
}

public static function numbersProvider(): \Generator
{
self::$ids = $ids = new IdsCollection();

$products = [
'p1' => self::product($ids, 'p1', 'DE-031668-B', 'HP LaserJet Enterprise M608x Inkl. Stapelfach und Papierfach'),
'p2' => self::product($ids, 'p2', 'DE-031677-B', 'HP LaserJet Enterprise M608x Inkl. Stapelfach'),
'p3' => self::product($ids, 'p3', 'DE-031687-B', 'HP LaserJet Enterprise M608x'),
'p4' => self::product($ids, 'p4', 'DE-13.116-B', 'LG 24MB35PM-B - 1920 x 1080 - FHD'),
'p5' => self::product($ids, 'p5', 'DE-15.174-N', 'Crucial DDR4 Desktop Speicher - DIMM - DDR4 - 2400 MHz - CL17'),
'p6' => self::product($ids, 'p6', 'DE-17.028-A', 'Fujitsu Display B24-8 TE - 1920 x 1080 - FHD'),
'p7' => self::product($ids, 'p7', 'DE-17.028-B', 'Fujitsu Display B24-8 TE - 1920 x 1080 - FHD'),
'p8' => self::product($ids, 'p8', 'DE-17.346-B', 'LG 24BK550Y-B - 1920 x 1080 - FHD'),
'p9' => self::product($ids, 'p9', 'DE-17.353-B', 'Eizo FlexScan EV2416W-BK - 1920 x 1200 - WUXGA'),
'p10' => self::product($ids, 'p10', 'DE-17.447-N', 'SOLID DDR3 Desktop Speicher - DIMM 240-PIN - DDR3 - 1600 MHz - CL 11'),
];

yield 'Exact number match' => [$products, 'DE-031668-B', 'p1'];
}

protected function getDiContainer(): ContainerInterface
{
return $this->getContainer();
}

protected function runWorker(): void
{
}

/**
* @return array<string, mixed>
*/
private static function product(IdsCollection $ids, string $key, string $number, string $name): array
{
return (new ProductBuilder($ids, $key))
->number($number)
->price(100)
->visibility()
->name($name)
->build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ public function testEmptyQueryExceptionIsCatched(): void
$client,
$this->createMock(EntityAggregatorInterface::class),
$this->createMock(AbstractElasticsearchAggregationHydrator::class),
new EventDispatcher()
new EventDispatcher(),
'10s',
'dfs_query_then_fetch'
);

$context = Context::createDefaultContext();
Expand Down Expand Up @@ -73,6 +75,7 @@ public function testAggregateWithTimeout(): void
'timeout' => '10s',
'size' => 0,
],
'search_type' => 'dfs_query_then_fetch',
])->willReturn([]);

$helper = $this->createMock(ElasticsearchHelper::class);
Expand All @@ -86,7 +89,8 @@ public function testAggregateWithTimeout(): void
$this->createMock(EntityAggregatorInterface::class),
$this->createMock(AbstractElasticsearchAggregationHydrator::class),
new EventDispatcher(),
'10s'
'10s',
'dfs_query_then_fetch'
);

$context = Context::createDefaultContext();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public function testEmptyQueryExceptionIsCatched(): void
$this->createMock(CriteriaParser::class),
$this->createMock(AbstractElasticsearchSearchHydrator::class),
new EventDispatcher(),
'10s',
'dfs_query_then_fetch'
);

$context = Context::createDefaultContext();
Expand Down Expand Up @@ -87,6 +89,8 @@ public function testWithCriteriaLimitOfZero(): void
$this->createMock(CriteriaParser::class),
$this->createMock(AbstractElasticsearchSearchHydrator::class),
new EventDispatcher(),
'5s',
'dfs_query_then_fetch'
);

$context = Context::createDefaultContext();
Expand Down Expand Up @@ -118,6 +122,7 @@ public function testSearchWithTimeout(): void
'from' => 0,
'size' => 10,
],
'search_type' => 'dfs_query_then_fetch',
])->willReturn([]);

$helper = $this->createMock(ElasticsearchHelper::class);
Expand All @@ -132,7 +137,8 @@ public function testSearchWithTimeout(): void
$this->createMock(CriteriaParser::class),
$this->createMock(AbstractElasticsearchSearchHydrator::class),
new EventDispatcher(),
'10s'
'10s',
'dfs_query_then_fetch'
);

$context = Context::createDefaultContext();
Expand Down Expand Up @@ -168,6 +174,8 @@ public function testExceptionsGetLogged(): void
new CriteriaParser(new EntityDefinitionQueryHelper(), $this->createMock(CustomFieldService::class)),
$this->createMock(AbstractElasticsearchSearchHydrator::class),
new EventDispatcher(),
'5s',
'dfs_query_then_fetch'
);

$context = Context::createDefaultContext();
Expand Down
Loading

0 comments on commit 6863c96

Please sign in to comment.