1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
use Elasticsearch\Client; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* phpMyFAQ Elasticsearch based search classes. |
7
|
|
|
* |
8
|
|
|
* PHP Version 5.5 |
9
|
|
|
* |
10
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public License, |
11
|
|
|
* v. 2.0. If a copy of the MPL was not distributed with this file, You can |
12
|
|
|
* obtain one at http://mozilla.org/MPL/2.0/. |
13
|
|
|
* |
14
|
|
|
* @category phpMyFAQ |
15
|
|
|
* @author Thorsten Rinne <[email protected]> |
16
|
|
|
* @copyright 2015-2016 phpMyFAQ Team |
17
|
|
|
* @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0 |
18
|
|
|
* @link http://www.phpmyfaq.de |
19
|
|
|
* @since 2015-12-25 |
20
|
|
|
*/ |
21
|
|
|
if (!defined('IS_VALID_PHPMYFAQ')) { |
22
|
|
|
exit(); |
23
|
|
|
} |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* PMF_Search_Elasticsearch. |
27
|
|
|
* |
28
|
|
|
* @category phpMyFAQ |
29
|
|
|
* @author Thorsten Rinne <[email protected]> |
30
|
|
|
* @copyright 2015-2016 phpMyFAQ Team |
31
|
|
|
* @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0 |
32
|
|
|
* @link http://www.phpmyfaq.de |
33
|
|
|
* @since 2015-12-25 |
34
|
|
|
*/ |
35
|
|
|
class PMF_Search_Elasticsearch extends PMF_Search_Abstract implements PMF_Search_Interface |
36
|
|
|
{ |
37
|
|
|
/** @var Client */ |
38
|
|
|
private $client = null; |
39
|
|
|
|
40
|
|
|
/** @var array */ |
41
|
|
|
private $esConfig = []; |
42
|
|
|
|
43
|
|
|
/** @var string */ |
44
|
|
|
private $language = ''; |
45
|
|
|
|
46
|
|
|
/** @var array */ |
47
|
|
|
private $categoryIds = []; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Constructor. |
51
|
|
|
* |
52
|
|
|
* @param PMF_Configuration |
53
|
|
|
*/ |
54
|
|
|
public function __construct(PMF_Configuration $config) |
55
|
|
|
{ |
56
|
|
|
parent::__construct($config); |
57
|
|
|
|
58
|
|
|
$this->client = $this->_config->getElasticsearch(); |
59
|
|
|
$this->esConfig = $this->_config->getElasticsearchConfig(); |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Prepares the search and executes it. |
64
|
|
|
* |
65
|
|
|
* @param string $searchTerm Search term |
66
|
|
|
* |
67
|
|
|
* @throws PMF_Search_Exception |
68
|
|
|
* |
69
|
|
|
* @return array |
70
|
|
|
*/ |
71
|
|
|
public function search($searchTerm) |
72
|
|
|
{ |
73
|
|
|
$searchParams = [ |
74
|
|
|
'index' => $this->esConfig['index'], |
75
|
|
|
'type' => $this->esConfig['type'], |
76
|
|
|
'size' => 1000, |
77
|
|
|
'body' => [ |
78
|
|
|
'query' => [ |
79
|
|
|
'filtered' => [ |
80
|
|
|
'filter' => [ |
81
|
|
|
'bool' => [ |
82
|
|
|
'must' => [ |
83
|
|
|
[ |
84
|
|
|
'terms' => ['category_id' => $this->getCategoryIds()] |
85
|
|
|
] |
86
|
|
|
] |
87
|
|
|
] |
88
|
|
|
], |
89
|
|
|
'query' => [ |
90
|
|
|
'multi_match' => [ |
91
|
|
|
'fields' => [ |
92
|
|
|
'question', 'answer', 'keywords' |
93
|
|
|
], |
94
|
|
|
'query' => $searchTerm, |
95
|
|
|
'fuzziness' => 'AUTO' |
96
|
|
|
] |
97
|
|
|
] |
98
|
|
|
] |
99
|
|
|
] |
100
|
|
|
] |
101
|
|
|
]; |
102
|
|
|
|
103
|
|
|
$result = $this->client->search($searchParams); |
104
|
|
|
|
105
|
|
View Code Duplication |
if (0 !== $result['hits']['total']) { |
|
|
|
|
106
|
|
|
|
107
|
|
|
foreach ($result['hits']['hits'] as $hit) { |
108
|
|
|
$resultSet = new stdClass(); |
109
|
|
|
$resultSet->id = $hit['_source']['id']; |
110
|
|
|
$resultSet->lang = $hit['_source']['lang']; |
111
|
|
|
$resultSet->question = $hit['_source']['question']; |
112
|
|
|
$resultSet->answer = $hit['_source']['answer']; |
113
|
|
|
$resultSet->keywords = $hit['_source']['keywords']; |
114
|
|
|
$resultSet->category_id = $hit['_source']['category_id']; |
115
|
|
|
$resultSet->score = $hit['_score']; |
116
|
|
|
|
117
|
|
|
$this->resultSet[] = $resultSet; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
} else { |
121
|
|
|
$this->resultSet = []; |
|
|
|
|
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
return $this->resultSet; |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* Prepares the autocomplete search and executes it. |
129
|
|
|
* |
130
|
|
|
* @param string $searchTerm Search term for autocompletion |
131
|
|
|
* |
132
|
|
|
* @throws PMF_Search_Exception |
133
|
|
|
* |
134
|
|
|
* @return array |
135
|
|
|
*/ |
136
|
|
|
public function autoComplete($searchTerm) |
137
|
|
|
{ |
138
|
|
|
$searchParams = [ |
139
|
|
|
'index' => $this->esConfig['index'], |
140
|
|
|
'type' => $this->esConfig['type'], |
141
|
|
|
'size' => 1000, |
142
|
|
|
'body' => [ |
143
|
|
|
'query' => [ |
144
|
|
|
'filtered' => [ |
145
|
|
|
'filter' => [ |
146
|
|
|
'term' => [ |
147
|
|
|
'lang' => $this->getLanguage() |
148
|
|
|
] |
149
|
|
|
], |
150
|
|
|
'query' => [ |
151
|
|
|
'multi_match' => [ |
152
|
|
|
'fields' => [ |
153
|
|
|
'question', 'answer', 'keywords' |
154
|
|
|
], |
155
|
|
|
'query' => $searchTerm, |
156
|
|
|
'fuzziness' => 'AUTO' |
157
|
|
|
] |
158
|
|
|
] |
159
|
|
|
] |
160
|
|
|
] |
161
|
|
|
] |
162
|
|
|
]; |
163
|
|
|
|
164
|
|
|
$result = $this->client->search($searchParams); |
165
|
|
|
|
166
|
|
View Code Duplication |
if (0 !== $result['hits']['total']) { |
|
|
|
|
167
|
|
|
|
168
|
|
|
foreach ($result['hits']['hits'] as $hit) { |
169
|
|
|
$resultSet = new stdClass(); |
170
|
|
|
$resultSet->id = $hit['_source']['id']; |
171
|
|
|
$resultSet->lang = $hit['_source']['lang']; |
172
|
|
|
$resultSet->question = $hit['_source']['question']; |
173
|
|
|
$resultSet->answer = $hit['_source']['answer']; |
174
|
|
|
$resultSet->keywords = $hit['_source']['keywords']; |
175
|
|
|
$resultSet->category_id = $hit['_source']['category_id']; |
176
|
|
|
$resultSet->score = $hit['_score']; |
177
|
|
|
|
178
|
|
|
$this->resultSet[] = $resultSet; |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
} else { |
182
|
|
|
$this->resultSet = []; |
|
|
|
|
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
return $this->resultSet; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Returns the current category ID |
190
|
|
|
* |
191
|
|
|
* @return array |
192
|
|
|
*/ |
193
|
|
|
public function getCategoryIds() |
194
|
|
|
{ |
195
|
|
|
return $this->categoryIds; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Sets the current category ID |
200
|
|
|
* |
201
|
|
|
* @param array $categoryIds |
202
|
|
|
*/ |
203
|
|
|
public function setCategoryIds(Array $categoryIds) |
204
|
|
|
{ |
205
|
|
|
$this->categoryIds = $categoryIds; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
/** |
209
|
|
|
* Returns the current language, empty string if all languages |
210
|
|
|
* |
211
|
|
|
* @return string |
212
|
|
|
*/ |
213
|
|
|
public function getLanguage() |
214
|
|
|
{ |
215
|
|
|
return $this->language; |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
/** |
219
|
|
|
* Sets the current language |
220
|
|
|
* |
221
|
|
|
* @param string $language |
222
|
|
|
*/ |
223
|
|
|
public function setLanguage($language) |
224
|
|
|
{ |
225
|
|
|
$this->language = $language; |
226
|
|
|
} |
227
|
|
|
} |
228
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.