Skip to content

Commit 6c0e948

Browse files
committed
Merge pull request #105 from daniellienert/feature-elasticsearch-suggestions
[FEATURE] implements the suggest feature of elasticsearch
2 parents 34f8973 + d2b11b8 commit 6c0e948

4 files changed

Lines changed: 142 additions & 1 deletion

File tree

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

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ public function fieldBasedAggregation($name, $field, $type = "terms", $parentPat
451451
* nodes = ${Search....aggregation("color", this.aggregationDefinition).execute()}
452452
*
453453
* Access all aggregation data with {nodes.aggregations} in your fluid template
454-
*
454+
*
455455
* @param string $name
456456
* @param array $aggregationDefinition
457457
* @param null $parentPath
@@ -501,6 +501,64 @@ protected function addSubAggregation($parentPath, $name, $aggregationConfigurati
501501
return $this;
502502
}
503503

504+
/**
505+
* This method is used to create a simple term suggestion.
506+
*
507+
* Example Usage of a term suggestion
508+
*
509+
* nodes = ${Search....termSuggestions("aTerm")}
510+
*
511+
* Access all suggestions data with {nodes.suggestions} in your fluid template
512+
*
513+
* @param string $text
514+
* @param string $field
515+
* @param string $name
516+
* @return $this
517+
*/
518+
public function termSuggestions($text, $field = '_all', $name = 'suggestions')
519+
{
520+
$suggestionDefinition = [
521+
'text' => $text,
522+
'term' => [
523+
'field' => $field
524+
]
525+
];
526+
527+
$this->suggestions($name, $suggestionDefinition);
528+
return $this;
529+
}
530+
531+
/**
532+
* This method is used to create any kind of suggestion.
533+
*
534+
* Example Usage of a term suggestion for the fulltext search
535+
*
536+
* suggestionDefinition = TYPO3.TypoScript:RawArray {
537+
* text = "some text"
538+
* terms = TYPO3.TypoScript:RawArray {
539+
* field = "body"
540+
* }
541+
* }
542+
*
543+
* nodes = ${Search....suggestion("my-suggestions", this.suggestionDefinition).execute()}
544+
*
545+
* Access all suggestions data with {nodes.suggestions} in your fluid template
546+
*
547+
* @param string $name
548+
* @param array $suggestionDefinition
549+
* @return $this
550+
*/
551+
public function suggestions($name, array $suggestionDefinition)
552+
{
553+
if (!array_key_exists('suggest', $this->request)) {
554+
$this->request['suggest'] = [];
555+
}
556+
557+
$this->request['suggest'][$name] = $suggestionDefinition;
558+
559+
return $this;
560+
}
561+
504562
/**
505563
* Get the ElasticSearch request as we need it
506564
*

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,22 @@ public function getAggregations()
198198
return array();
199199
}
200200

201+
/**
202+
* @return array
203+
*/
204+
public function getSuggestions()
205+
{
206+
$this->initialize();
207+
if (count($this->result['suggest']) === 1) {
208+
$suggestArray = current($this->result['suggest']);
209+
210+
if (count($suggestArray) === 1) {
211+
return current($suggestArray);
212+
}
213+
}
214+
return $this->result['suggest'];
215+
}
216+
201217
/**
202218
* Returns the ElasticSearch "hit" (e.g. the raw content being transferred back from ElasticSearch)
203219
* for the given node.
@@ -222,3 +238,4 @@ public function allowsCallOfMethod($methodName)
222238
return true;
223239
}
224240
}
241+

README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,50 @@ of `__typeAndSupertypes` containing `TYPO3.Neos:Document`.
393393

394394
**For a search user interface, checkout the Flowpack.SearchPlugin package**
395395

396+
## Suggestions
397+
398+
Elasticsearch offers an easy way to get query suggestions based on your query. Check
399+
`https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters.html` for more information about how
400+
you can build and use suggestion in your search.
401+
402+
**Suggestion methods implemented**
403+
There are two methods implemented. `suggestions` is a generic one that allows to build the suggestion query of your
404+
dreams. The other method is `termSuggestions` and is meant for basic term suggestions. They can be added to your totaly
405+
awesome TS search query.
406+
407+
* `suggestions($name, array $suggestionDefinition)` -- generic method to be filled with your own suggestionQuery
408+
* `termSuggestions($term, $field = '_all', $name = 'suggestions'` -- simple term suggestion query on all fields
409+
410+
### Examples
411+
#### Add a simple suggestion to a query
412+
Simple suggestion that returns a suggestion based on the sent term
413+
414+
```
415+
suggestions = $(Search.query(site)...termSuggestions('someTerm')}
416+
```
417+
You can access your suggestions inside your fluid template with
418+
```
419+
{nodes.suggestions}
420+
```
421+
422+
### Add a custom suggestion
423+
Phrase query that returns query suggestions
424+
425+
```
426+
suggestionsQueryDefinition = TYPO3.TypoScript:RawArray {
427+
text = 'some Text'
428+
simple_phrase = TYPO3.TypoScript:RawArray {
429+
phrase = TYPO3.TypoScript:RawArray {
430+
analyzer = 'body'
431+
field = 'bigram'
432+
size = 1
433+
real_world_error_likelihood = 0.95
434+
...
435+
}
436+
}
437+
}
438+
suggestions = ${Search.query(site)...suggestions('my_suggestions', this.suggestionsQueryDefinition)}
439+
```
396440

397441
## Advanced: Configuration of Indexing
398442

Tests/Functional/Eel/ElasticSearchQueryTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,28 @@ public function fieldBasedAggregations()
143143
$this->assertEquals($expectedChickenBucket, $result[$aggregationTitle]['buckets'][0]);
144144
}
145145

146+
/**
147+
* @test
148+
*/
149+
public function termSuggestion()
150+
{
151+
$titleSuggestionKey = "chickn";
152+
153+
$result = $this->queryBuilder->query($this->context->getRootNode())->termSuggestions($titleSuggestionKey, "title")->execute()->getSuggestions();
154+
155+
$this->assertArrayHasKey("options", $result);
156+
157+
$this->assertCount(1, $result['options']);
158+
159+
$expectedChickenBucket = array(
160+
'text' => 'chicken',
161+
'freq' => 2,
162+
'score' => 0.8333333
163+
);
164+
165+
$this->assertEquals($expectedChickenBucket, $result['options'][0]);
166+
}
167+
146168
/**
147169
* @test
148170
*/

0 commit comments

Comments
 (0)