Skip to content

Commit f1b2fa9

Browse files
committed
MERGE: Merge branch '2.0' into master
2 parents 3071a6f + cf0a7eb commit f1b2fa9

6 files changed

Lines changed: 112 additions & 20 deletions

File tree

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ before_install:
1515
- git clone https://github.com/neos/neos-base-distribution.git
1616
- cd neos-base-distribution
1717
- composer require flowpack/elasticsearch-contentrepositoryadaptor dev-master
18+
- composer require typo3/typo3cr-search dev-master
1819
install:
1920
- composer install
2021
- cd ..

Classes/Flowpack/ElasticSearch/ContentRepositoryAdaptor/Eel/ElasticSearchQueryBuilder.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Flowpack\ElasticSearch\ContentRepositoryAdaptor\Exception\QueryBuildingException;
1515
use TYPO3\Eel\ProtectedContextAwareInterface;
1616
use TYPO3\Flow\Annotations as Flow;
17+
use TYPO3\Flow\Utility\Arrays;
1718
use TYPO3\TYPO3CR\Domain\Model\NodeInterface;
1819
use TYPO3\TYPO3CR\Search\Search\QueryBuilderInterface;
1920

@@ -101,7 +102,9 @@ class ElasticSearchQueryBuilder implements QueryBuilderInterface, ProtectedConte
101102
[
102103
'match_all' => []
103104
]
104-
]
105+
],
106+
'should' => [],
107+
'must_not' => []
105108
]
106109

107110
],
@@ -790,6 +793,28 @@ public function query(NodeInterface $contextNode)
790793
return $this;
791794
}
792795

796+
/**
797+
* Modify a part of the Elasticsearch Request denoted by $path, merging together
798+
* the existing values and the passed-in values.
799+
*
800+
* @param string $path
801+
* @param mixed $requestPart
802+
* @return $this
803+
*/
804+
public function request($path, $requestPart)
805+
{
806+
$valueAtPath = Arrays::getValueByPath($this->request, $path);
807+
if (is_array($valueAtPath)) {
808+
$result = Arrays::arrayMergeRecursiveOverrule($valueAtPath, $requestPart);
809+
} else {
810+
$result = $requestPart;
811+
}
812+
813+
$this->request = Arrays::setValueByPath($this->request, $path, $result);
814+
815+
return $this;
816+
}
817+
793818
/**
794819
* All methods are considered safe
795820
*

Classes/Flowpack/ElasticSearch/ContentRepositoryAdaptor/Indexer/NodeIndexer.php

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use TYPO3\TYPO3CR\Domain\Service\ContextFactory;
2323
use TYPO3\TYPO3CR\Domain\Service\NodeTypeManager;
2424
use TYPO3\TYPO3CR\Search\Indexer\AbstractNodeIndexer;
25+
use TYPO3\TYPO3CR\Search\Indexer\BulkNodeIndexerInterface;
2526

2627
/**
2728
* Indexer for Content Repository Nodes. Triggered from the NodeIndexingManager.
@@ -30,7 +31,7 @@
3031
*
3132
* @Flow\Scope("singleton")
3233
*/
33-
class NodeIndexer extends AbstractNodeIndexer
34+
class NodeIndexer extends AbstractNodeIndexer implements BulkNodeIndexerInterface
3435
{
3536
/**
3637
* Optional postfix for the index, e.g. to have different indexes by timestamp.
@@ -88,6 +89,11 @@ class NodeIndexer extends AbstractNodeIndexer
8889
*/
8990
protected $currentBulkRequest = [];
9091

92+
/**
93+
* @var boolean
94+
*/
95+
protected $bulkProcessing = false;
96+
9197
/**
9298
* Returns the index name to be used for indexing, with optional indexNamePostfix appended.
9399
*
@@ -162,24 +168,26 @@ public function indexNode(NodeInterface $node, $targetWorkspaceName = null)
162168

163169
$mappingType = $this->getIndex()->findType(NodeTypeMappingBuilder::convertNodeTypeNameToMappingName($nodeType));
164170

165-
// Remove document with the same contextPathHash but different NodeType, required after NodeType change
166-
$this->logger->log(sprintf('NodeIndexer: Removing node %s from index (if node type changed from %s). ID: %s', $contextPath, $node->getNodeType()->getName(), $contextPathHash), LOG_DEBUG, null, 'ElasticSearch (CR)');
167-
$this->getIndex()->request('DELETE', '/_query', [], json_encode([
168-
'query' => [
169-
'bool' => [
170-
'must' => [
171-
'ids' => [
172-
'values' => [$contextPathHash]
173-
]
174-
],
175-
'must_not' => [
176-
'term' => [
177-
'_type' => NodeTypeMappingBuilder::convertNodeTypeNameToMappingName($node->getNodeType()->getName())
178-
]
179-
],
171+
if ($this->bulkProcessing === false) {
172+
// Remove document with the same contextPathHash but different NodeType, required after NodeType change
173+
$this->logger->log(sprintf('NodeIndexer: Search and remove duplicate document if needed. ID: %s', $contextPath, $node->getNodeType()->getName(), $contextPathHash), LOG_DEBUG, null, 'ElasticSearch (CR)');
174+
$this->getIndex()->request('DELETE', '/_query', [], json_encode([
175+
'query' => [
176+
'bool' => [
177+
'must' => [
178+
'ids' => [
179+
'values' => [$contextPathHash]
180+
]
181+
],
182+
'must_not' => [
183+
'term' => [
184+
'_type' => NodeTypeMappingBuilder::convertNodeTypeNameToMappingName($node->getNodeType()->getName())
185+
]
186+
],
187+
]
180188
]
181-
]
182-
]));
189+
]));
190+
}
183191

184192
if ($node->isRemoved()) {
185193
// TODO: handle deletion from the fulltext index as well
@@ -541,4 +549,26 @@ public function removeOldIndices()
541549

542550
return $indicesToBeRemoved;
543551
}
552+
553+
/**
554+
* Perform indexing without checking about duplication document
555+
*
556+
* This is used during bulk indexing to improve performance
557+
*
558+
* @param callable $callback
559+
* @throws \Exception
560+
*/
561+
public function withBulkProcessing(callable $callback)
562+
{
563+
$bulkProcessing = $this->bulkProcessing;
564+
$this->bulkProcessing = true;
565+
try {
566+
/** @noinspection PhpUndefinedMethodInspection */
567+
$callback->__invoke();
568+
} catch (\Exception $exception) {
569+
$this->bulkProcessing = $bulkProcessing;
570+
throw $exception;
571+
}
572+
$this->bulkProcessing = $bulkProcessing;
573+
}
544574
}

Classes/Flowpack/ElasticSearch/ContentRepositoryAdaptor/Service/IndexWorkspaceTrait.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ protected function indexWorkspaceWithDimensions($workspaceName, array $dimension
8484

8585
$traverseNodes($rootNode, $indexedNodes);
8686

87+
$this->nodeFactory->reset();
88+
$context->getFirstLevelNodeCache()->flush();
89+
8790
if ($callback !== null) {
8891
$callback($workspaceName, $indexedNodes, $dimensions);
8992
}

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,11 @@ Furthermore, there is a more low-level operator which can be used to add arbitra
224224

225225
* `queryFilter("filterType", {option1: "value1"})`
226226

227+
At lowest level, there is the `request` operator which allows to modify the request in arbitrary manner. Note that the existing request is merged with the passed-in type in case it is an array:
228+
229+
* `request('query.filtered.query.bool.minimum_should_match', 1)`
230+
* `request('query.filtered.query.bool', {"minimum_should_match": 1})`
231+
227232
In order to debug the query more easily, the following operation is helpful:
228233

229234
* `log()` log the full query on execution into the Elasticsearch log (i.e. in `Data/Logs/ElasticSearch.log`)

Tests/Unit/Eel/ElasticSearchQueryBuilderTest.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ public function basicRequestStructureTakesContextNodeIntoAccount()
5555
'bool' => [
5656
'must' => [
5757
['match_all' => []]
58-
]
58+
],
59+
'should' => [],
60+
'must_not' => []
5961
]
6062
],
6163
'filter' => [
@@ -326,6 +328,32 @@ public function aCustomAggregationDefinitionCanBeApplied()
326328
$this->assertInArray($expected, $actual);
327329
}
328330

331+
/**
332+
* @test
333+
*/
334+
public function requestCanBeExtendedByArbitraryProperties()
335+
{
336+
$this->queryBuilder->request('foo.bar', ['field' => 'x']);
337+
$expected = [
338+
'bar' => ['field' => 'x']
339+
];
340+
$actual = $this->queryBuilder->getRequest();
341+
$this->assertEquals($expected, $actual['foo']);
342+
}
343+
344+
/**
345+
* @test
346+
*/
347+
public function existingRequestPropertiesCanBeOverridden()
348+
{
349+
$this->queryBuilder->limit(2);
350+
$this->queryBuilder->request('limit', 10);
351+
$expected = 10;
352+
$actual = $this->queryBuilder->getRequest();
353+
$this->assertEquals($expected, $actual['limit']);
354+
}
355+
356+
329357
/**
330358
* Test helper
331359
*

0 commit comments

Comments
 (0)