1313
1414use Flowpack \ElasticSearch \ContentRepositoryAdaptor \Eel \ElasticSearchQueryBuilder ;
1515use Flowpack \ElasticSearch \ContentRepositoryAdaptor \Eel \ElasticSearchQueryResult ;
16+ use Flowpack \ElasticSearch \ContentRepositoryAdaptor \ElasticSearchClient ;
17+ use Neos \Cache \Frontend \VariableFrontend ;
1618use Neos \ContentRepository \Domain \Model \NodeInterface ;
1719use Neos \Flow \Annotations as Flow ;
1820use Neos \Flow \Mvc \Controller \ActionController ;
1921use Neos \Flow \Mvc \View \JsonView ;
22+ use Neos \Neos \Controller \CreateContentContextTrait ;
2023
21- /**
22- * Class SuggestController
23- */
2424class SuggestController extends ActionController
2525{
26+ use CreateContentContextTrait;
27+
28+ /**
29+ * @Flow\Inject
30+ * @var ElasticSearchClient
31+ */
32+ protected $ elasticSearchClient ;
33+
2634 /**
2735 * @Flow\Inject
2836 * @var ElasticSearchQueryBuilder
2937 */
3038 protected $ elasticSearchQueryBuilder ;
3139
40+ /**
41+ * @Flow\Inject
42+ * @var VariableFrontend
43+ */
44+ protected $ elasticSearchQueryTemplateCache ;
45+
3246 /**
3347 * @var array
3448 */
@@ -37,11 +51,11 @@ class SuggestController extends ActionController
3751 ];
3852
3953 /**
40- * @param NodeInterface $contextNode
54+ * @param string $contextNodeIdentifier
4155 * @param string $term
4256 * @return void
4357 */
44- public function indexAction (NodeInterface $ contextNode , $ term )
58+ public function indexAction ($ contextNodeIdentifier , $ term )
4559 {
4660 $ result = [
4761 'completions ' => [],
@@ -54,64 +68,103 @@ public function indexAction(NodeInterface $contextNode, $term)
5468 return ;
5569 }
5670
71+ $ requestJson = $ this ->buildRequestForTerm ($ term , $ contextNodeIdentifier );
72+
73+ try {
74+ $ response = $ this ->elasticSearchClient ->getIndex ()->request ('POST ' , '/_search ' , [], $ requestJson )->getTreatedContent ();
75+ $ result ['completions ' ] = $ this ->extractCompletions ($ response );
76+ $ result ['suggestions ' ] = $ this ->extractSuggestions ($ response );
77+ } catch (\Exception $ e ) {
78+ $ result ['errors ' ] = ['Could not execute query ' ];
79+ }
80+
81+ $ this ->view ->assign ('value ' , $ result );
82+ }
83+
84+ /**
85+ * @param string $term
86+ * @param string $contextNodeIdentifier
87+ * @return ElasticSearchQueryBuilder
88+ */
89+ protected function buildRequestForTerm ($ term , $ contextNodeIdentifier )
90+ {
91+ $ termPlaceholder = '---term-soh2gufuNi--- ' ;
5792 $ term = strtolower ($ term );
5893
59- // TODO: cache query by node identifier
60-
61- /** @var ElasticSearchQueryBuilder $query */
62- $ query = $ this ->elasticSearchQueryBuilder ->query ($ contextNode );
63- $ query
64- ->queryFilter ('prefix ' , [
65- '__completion ' => $ term
66- ])
67- ->limit (0 )
68- ->aggregation ('autocomplete ' , [
69- 'terms ' => [
70- 'field ' => '__completion ' ,
71- 'order ' => [
72- '_count ' => 'desc '
73- ],
74- 'include ' => [
75- 'pattern ' => $ term . '.* '
94+ if (!$ this ->elasticSearchQueryTemplateCache ->has ($ contextNodeIdentifier )) {
95+
96+ $ contentContext = $ this ->createContentContext ('live ' , []);
97+ $ contextNode = $ contentContext ->getNodeByIdentifier ($ contextNodeIdentifier );
98+
99+ /** @var ElasticSearchQueryBuilder $query */
100+ $ query = $ this ->elasticSearchQueryBuilder ->query ($ contextNode );
101+ $ query
102+ ->queryFilter ('prefix ' , [
103+ '__completion ' => $ termPlaceholder
104+ ])
105+ ->limit (1 )
106+ ->aggregation ('autocomplete ' , [
107+ 'terms ' => [
108+ 'field ' => '__completion ' ,
109+ 'order ' => [
110+ '_count ' => 'desc '
111+ ],
112+ 'include ' => [
113+ 'pattern ' => $ termPlaceholder . '.* '
114+ ]
76115 ]
77- ]
78- ])
79- -> suggestions ( ' suggestions ' , [
80- ' text ' => $ term ,
81- ' completion ' => [
82- ' field ' => ' __suggestions ' ,
83- ' fuzzy ' => true ,
84- ' context ' => [
85- ' parentPath ' => $ contextNode -> getPath () ,
86- ' workspace ' => ' live ' ,
87- ' dimensionCombinationHash ' => md5 ( json_encode ( $ contextNode -> getContext ()-> getDimensions ())),
116+ ])
117+ -> suggestions ( ' suggestions ' , [
118+ ' text ' => $ termPlaceholder ,
119+ ' completion ' => [
120+ ' field ' => ' __suggestions ' ,
121+ ' fuzzy ' => true ,
122+ ' context ' => [
123+ ' parentPath ' => $ contextNode -> getPath (),
124+ ' workspace ' => ' live ' ,
125+ ' dimensionCombinationHash ' => md5 ( json_encode ( $ contextNode -> getContext ()-> getDimensions ())) ,
126+ ]
88127 ]
89- ]
90- ]);
128+ ]);
91129
92- try {
93- /** @var ElasticSearchQueryResult $queryResult */
94- $ queryResult = $ query ->execute ();
95- } catch (\Exception $ e ) {
96- $ result ['errors ' ] = ['Could not execute query ' ];
97- $ this ->view ->assign ('value ' , $ result );
98- return ;
130+ $ requestTemplate = $ query ->getRequest ()->getRequestAsJson ();
131+
132+ $ this ->elasticSearchQueryTemplateCache ->set ($ contextNodeIdentifier , $ requestTemplate );
133+ } else {
134+ $ requestTemplate = $ this ->elasticSearchQueryTemplateCache ->get ($ contextNodeIdentifier );
99135 }
100136
101- $ aggregations = $ queryResult ->getAggregations ();
137+ return str_replace ($ termPlaceholder , $ term , $ requestTemplate );
138+ }
139+
140+ /**
141+ * Extract autocomplete options
142+ *
143+ * @param $response
144+ * @return array
145+ */
146+ protected function extractCompletions ($ response )
147+ {
148+ $ aggregations = isset ($ response ['aggregations ' ]) ? $ response ['aggregations ' ] : [];
102149
103- // Extract autocomplete options
104- $ autoCompletionOptions = array_map (function ($ option ) {
150+ return array_map (function ($ option ) {
105151 return $ option ['key ' ];
106152 }, $ aggregations ['autocomplete ' ]['buckets ' ]);
107- $ result [ ' completions ' ] = $ autoCompletionOptions ;
153+ }
108154
109- // Extract suggestion options
110- $ suggestionOptions = $ queryResult ->getSuggestions ();
155+ /**
156+ * Extract suggestion options
157+ *
158+ * @param $response
159+ * @return array
160+ */
161+ protected function extractSuggestions ($ response )
162+ {
163+ $ suggestionOptions = isset ($ response ['suggest ' ]) ? $ response ['suggest ' ] : [];
111164 if (count ($ suggestionOptions ['suggestions ' ][0 ]['options ' ]) > 0 ) {
112- $ result [ ' suggestions ' ] = $ suggestionOptions ['suggestions ' ][0 ]['options ' ];
165+ return $ suggestionOptions ['suggestions ' ][0 ]['options ' ];
113166 }
114167
115- $ this -> view -> assign ( ' value ' , $ result ) ;
168+ return [] ;
116169 }
117170}
0 commit comments