Skip to content

Commit 1fb6f0a

Browse files
Merge pull request #350 from DrillSergeant/bugfix/add-indexname-to-query-cache-hash
BUGIFX: Add indexname to query hash to prevent sharing query results of other indexes
2 parents 114323e + ff5ee48 commit 1fb6f0a

11 files changed

Lines changed: 499 additions & 199 deletions

Classes/Command/NodeIndexCommandController.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -268,10 +268,12 @@ public function buildCommand(int $limit = null, bool $update = false, string $wo
268268

269269
$runAndLog($createIndicesAndApplyMapping, 'Creating indices and apply mapping');
270270

271-
$timeStart = microtime(true);
272-
$this->output(str_pad('Indexing nodes ... ', 20));
273-
$buildIndex([]);
274-
$this->outputLine('<success>Done</success> (took %s seconds)', [number_format(microtime(true) - $timeStart, 2)]);
271+
// $timeStart = microtime(true);
272+
// $this->output(str_pad('Indexing nodes ... ', 20));
273+
// $buildIndex([]);
274+
// $this->outputLine('<success>Done</success> (took %s seconds)', [number_format(microtime(true) - $timeStart, 2)]);
275+
276+
$runAndLog($buildIndex, 'Indexing nodes');
275277

276278
$runAndLog($refresh, 'Refresh indicies');
277279
$runAndLog($updateAliases, 'Update aliases');

Classes/Eel/ElasticSearchQuery.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public function __construct(ElasticSearchQueryBuilder $elasticSearchQueryBuilder
5353
*/
5454
public function execute($cacheResult = false)
5555
{
56-
$queryHash = md5(json_encode($this->queryBuilder->getRequest()));
56+
$queryHash = md5($this->queryBuilder->getIndexName() . json_encode($this->queryBuilder->getRequest()));
5757
if ($cacheResult === true && isset(self::$runtimeQueryResultCache[$queryHash])) {
5858
return self::$runtimeQueryResultCache[$queryHash];
5959
}

Configuration/Testing/NodeTypes.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,20 @@
1717
search:
1818
elasticSearchMapping:
1919
type: text
20+
21+
'Flowpack.ElasticSearch.ContentRepositoryAdaptor:Document':
22+
superTypes:
23+
'Neos.Neos:Document': true
24+
childNodes:
25+
main:
26+
type: 'Neos.Neos:ContentCollection'
27+
28+
'Flowpack.ElasticSearch.ContentRepositoryAdaptor:Content':
29+
superTypes:
30+
'Neos.Neos:Content': true
31+
properties:
32+
text:
33+
type: string
34+
defaultValue: ''
35+
search:
36+
fulltextExtractor: '${Indexing.extractHtmlTags(value)}'
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Flowpack\ElasticSearch\ContentRepositoryAdaptor\Tests\Functional;
5+
6+
/*
7+
* This file is part of the Flowpack.ElasticSearch.ContentRepositoryAdaptor package.
8+
*
9+
* (c) Contributors of the Neos Project - www.neos.io
10+
*
11+
* This package is Open Source Software. For the full copyright and license
12+
* information, please view the LICENSE file which was distributed with this
13+
* source code.
14+
*/
15+
16+
use Flowpack\ElasticSearch\ContentRepositoryAdaptor\Command\NodeIndexCommandController;
17+
use Flowpack\ElasticSearch\ContentRepositoryAdaptor\Eel\ElasticSearchQueryBuilder;
18+
use Flowpack\ElasticSearch\ContentRepositoryAdaptor\ElasticSearchClient;
19+
use Neos\ContentRepository\Domain\Service\ContextFactory;
20+
use Neos\Flow\Tests\FunctionalTestCase;
21+
22+
abstract class BaseElasticsearchContentRepositoryAdapterTest extends FunctionalTestCase
23+
{
24+
protected const TESTING_INDEX_PREFIX = 'neoscr_testing';
25+
26+
/**
27+
* @var boolean
28+
*/
29+
protected static $testablePersistenceEnabled = true;
30+
31+
/**
32+
* @var NodeIndexCommandController
33+
*/
34+
protected $nodeIndexCommandController;
35+
36+
/**
37+
* @var ElasticSearchClient
38+
*/
39+
protected $searchClient;
40+
41+
protected static $instantiatedIndexes = [];
42+
43+
public function setUp(): void
44+
{
45+
parent::setUp();
46+
47+
$this->nodeIndexCommandController = $this->objectManager->get(NodeIndexCommandController::class);
48+
$this->searchClient = $this->objectManager->get(ElasticSearchClient::class);
49+
}
50+
51+
public function tearDown(): void
52+
{
53+
parent::tearDown();
54+
55+
if (isset($this->contextFactory) && $this->contextFactory instanceof ContextFactory) {
56+
$this->inject($this->contextFactory, 'contextInstances', []);
57+
}
58+
59+
if (!$this->isIndexInitialized()) {
60+
// clean up any existing indices
61+
$this->searchClient->request('DELETE', '/' . self::TESTING_INDEX_PREFIX . '*');
62+
}
63+
}
64+
65+
/**
66+
* @param string $method
67+
* @return string
68+
*/
69+
protected function getLogMessagePrefix(string $method): string
70+
{
71+
return substr(strrchr($method, '\\'), 1);
72+
}
73+
74+
protected function indexNodes(): void
75+
{
76+
if ($this->isIndexInitialized()) {
77+
return;
78+
}
79+
80+
$this->nodeIndexCommandController->buildCommand(null, false, null, 'functionaltest');
81+
$this->setIndexInitialized();
82+
}
83+
84+
/**
85+
* @return ElasticSearchQueryBuilder
86+
*/
87+
protected function getQueryBuilder(): ElasticSearchQueryBuilder
88+
{
89+
try {
90+
/** @var ElasticSearchQueryBuilder $elasticSearchQueryBuilder */
91+
$elasticSearchQueryBuilder = $this->objectManager->get(ElasticSearchQueryBuilder::class);
92+
$this->inject($elasticSearchQueryBuilder, 'now', new \DateTimeImmutable('@1735685400')); // Dec. 31, 2024 23:50:00
93+
94+
return $elasticSearchQueryBuilder;
95+
} catch (\Exception $exception) {
96+
static::fail('Setting up the QueryBuilder failed: ' . $exception->getMessage());
97+
}
98+
}
99+
100+
protected function isIndexInitialized(): bool
101+
{
102+
return self::$instantiatedIndexes[get_class($this)] ?? false;
103+
}
104+
105+
protected function setIndexInitialized(): void
106+
{
107+
self::$instantiatedIndexes[get_class($this)] = true;
108+
}
109+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Flowpack\ElasticSearch\ContentRepositoryAdaptor\Tests\Functional\Eel;
5+
6+
/*
7+
* This file is part of the Flowpack.ElasticSearch.ContentRepositoryAdaptor package.
8+
*
9+
* (c) Contributors of the Neos Project - www.neos.io
10+
*
11+
* This package is Open Source Software. For the full copyright and license
12+
* information, please view the LICENSE file which was distributed with this
13+
* source code.
14+
*/
15+
16+
use Flowpack\ElasticSearch\ContentRepositoryAdaptor\Tests\Functional\BaseElasticsearchContentRepositoryAdapterTest;
17+
use Flowpack\ElasticSearch\ContentRepositoryAdaptor\Tests\Functional\Traits\Assertions;
18+
use Flowpack\ElasticSearch\ContentRepositoryAdaptor\Tests\Functional\Traits\ContentRepositoryMultiDimensionNodeCreationTrait;
19+
use Flowpack\ElasticSearch\ContentRepositoryAdaptor\Tests\Functional\Traits\ContentRepositorySetupTrait;
20+
use Neos\ContentRepository\Domain\Model\NodeInterface;
21+
22+
class ElasticSearchMultiDimensionQueryTest extends BaseElasticsearchContentRepositoryAdapterTest
23+
{
24+
use ContentRepositorySetupTrait, ContentRepositoryMultiDimensionNodeCreationTrait, Assertions;
25+
26+
/**
27+
* @var NodeInterface
28+
*/
29+
protected $siteNodeDefault;
30+
31+
/**
32+
* @var NodeInterface
33+
*/
34+
protected $siteNodeDe;
35+
36+
/**
37+
* @var NodeInterface
38+
*/
39+
protected $siteNodeDk;
40+
41+
public function setUp(): void
42+
{
43+
parent::setUp();
44+
45+
$this->setupContentRepository();
46+
$this->createNodesForNodeSearchTest();
47+
$this->indexNodes();
48+
}
49+
50+
/**
51+
* @test
52+
*/
53+
public function countDefaultDimensionNodesTest(): void
54+
{
55+
$resultDefault = $this->getQueryBuilder()
56+
->query($this->siteNodeDefault)
57+
->log($this->getLogMessagePrefix(__METHOD__))
58+
->nodeType('Flowpack.ElasticSearch.ContentRepositoryAdaptor:Document')
59+
->sortDesc('title')
60+
->execute();
61+
62+
static::assertCount(3, $resultDefault->toArray());
63+
static::assertNodeNames(['root', 'document1', 'document-untranslated'], $resultDefault);
64+
}
65+
66+
/**
67+
* @test
68+
*/
69+
public function countDeDimensionNodesTest(): void
70+
{
71+
$resultDe = $this->getQueryBuilder()
72+
->query($this->siteNodeDe)
73+
->log($this->getLogMessagePrefix(__METHOD__))
74+
->nodeType('Flowpack.ElasticSearch.ContentRepositoryAdaptor:Document')
75+
->sortDesc('title')
76+
->execute();
77+
78+
// expecting: root, document1, document2, document3, document4, untranslated (fallback from en_us) = 6
79+
static::assertCount(6, $resultDe->toArray(), 'Found nodes: ' . implode(',', self::extractNodeNames($resultDe)));
80+
static::assertNodeNames(['root', 'document1', 'document2-de', 'document3-de', 'document4-de', 'document-untranslated'], $resultDe);
81+
}
82+
83+
/**
84+
* @test
85+
*/
86+
public function countDkDimensionNodesTest(): void
87+
{
88+
$resultDk = $this->getQueryBuilder()
89+
->query($this->siteNodeDk)
90+
->log($this->getLogMessagePrefix(__METHOD__))
91+
->nodeType('Flowpack.ElasticSearch.ContentRepositoryAdaptor:Document')
92+
->sortDesc('title')
93+
->execute();
94+
95+
// expecting: root, document1, document2, document4 (fallback from de), untranslated (fallback from en_us) = 6
96+
static::assertCount(5, $resultDk->toArray());
97+
static::assertNodeNames(['root', 'document1', 'document2-dk', 'document4-de', 'document-untranslated'], $resultDk);
98+
}
99+
}

0 commit comments

Comments
 (0)