1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Bardex\Elastic; |
4
|
|
|
|
5
|
|
|
use Bardex\Elastic\SearchResult; |
6
|
|
|
|
7
|
|
|
|
8
|
|
|
/** |
9
|
|
|
* Fluent interface for ElasticSearch |
10
|
|
|
* @package Bardex\Elastic |
11
|
|
|
*/ |
12
|
|
|
class SearchQuery extends Query |
13
|
|
|
{ |
14
|
|
|
/** |
15
|
|
|
* Параметры запроса |
16
|
|
|
* @var array |
17
|
|
|
*/ |
18
|
|
|
protected $params = []; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* @var Where |
22
|
|
|
*/ |
23
|
|
|
protected $whereHelper; |
24
|
|
|
|
25
|
|
|
|
26
|
|
|
public function __clone() |
27
|
|
|
{ |
28
|
|
|
$this->whereHelper = new Where($this); |
29
|
|
|
} |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* @return SearchQuery |
33
|
|
|
*/ |
34
|
|
|
public function fork() |
35
|
|
|
{ |
36
|
|
|
$copy = clone $this; |
37
|
|
|
return $copy; |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* Установить имя индекса для поиска |
42
|
|
|
* @param $index |
43
|
|
|
* @return self $this |
44
|
|
|
*/ |
45
|
|
|
public function setIndex($index) |
46
|
|
|
{ |
47
|
|
|
$this->params['index'] = (string) $index; |
48
|
|
|
return $this; |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Установить имя типа для поиска |
53
|
|
|
* @param $type |
54
|
|
|
* @return self $this |
55
|
|
|
*/ |
56
|
|
|
public function setType($type) |
57
|
|
|
{ |
58
|
|
|
$this->params['type'] = (string) $type; |
59
|
|
|
return $this; |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Выводить перечисленные поля. |
65
|
|
|
* (не обязательный метод, по-умолчанию, выводятся все) |
66
|
|
|
* Методы select() и exclude() могут работать совместно. |
67
|
|
|
* @param array $fields |
68
|
|
|
* @return self $this; |
69
|
|
|
* @example $query->select(['id', 'title', 'brand.id', 'brand.title']); |
70
|
|
|
*/ |
71
|
|
|
public function select(array $fields) |
72
|
|
|
{ |
73
|
|
|
$this->params['body']['_source']['includes'] = $fields; |
74
|
|
|
return $this; |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* Добавить в результаты вычисляемое поле, на скриптовом языке painless или groovy |
80
|
|
|
* @param string $fieldName - имя поля в результатах (если такое поле уже есть в документе, то оно будет заменено) |
81
|
|
|
* @param Script $script - скрипт |
82
|
|
|
* @link https://www.elastic.co/guide/en/elasticsearch/reference/5.0/search-request-script-fields.html |
83
|
|
|
* @return self $this |
84
|
|
|
*/ |
85
|
|
|
public function addScriptField($fieldName, Script $script) |
86
|
|
|
{ |
87
|
|
|
$this->params['body']['script_fields'][$fieldName] = $script->compile(); |
88
|
|
|
return $this; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* Удалить из выборки поля. |
94
|
|
|
* (не обязательный метод, по-умолчанию, выводятся все) |
95
|
|
|
* Методы select() и exclude() могут работать совместно. |
96
|
|
|
* @param array $fields |
97
|
|
|
* @return self $this; |
98
|
|
|
* @example $query->exclude(['anons', '*.anons']); |
99
|
|
|
*/ |
100
|
|
|
public function exclude(array $fields) |
101
|
|
|
{ |
102
|
|
|
$this->params['body']['_source']['excludes'] = $fields; |
103
|
|
|
return $this; |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* Добавить фильтр в raw формате, если готовые методы фильтрации не подходят. |
109
|
|
|
* |
110
|
|
|
* @param string $type - тип фильтрации (term|terms|match|range) |
111
|
|
|
* @param $filter - фильтр |
112
|
|
|
* @link https://www.elastic.co/guide/en/elasticsearch/reference/5.0/query-dsl-terms-query.html |
113
|
|
|
* @return self $this |
114
|
|
|
*/ |
115
|
|
View Code Duplication |
public function addFilter($type, $filter) |
|
|
|
|
116
|
|
|
{ |
117
|
|
|
if (!isset($this->params['body']['query']['bool']['must'])) { |
118
|
|
|
$this->params['body']['query']['bool']['must'] = []; |
119
|
|
|
} |
120
|
|
|
$this->params['body']['query']['bool']['must'][] = [$type => $filter]; |
121
|
|
|
return $this; |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* Добавить отрицательный фильтр в raw формате, если готовые методы фильтрации не подходят. |
126
|
|
|
* |
127
|
|
|
* @param string $type - тип фильтрации (term|terms|match|range) |
128
|
|
|
* @param $filter - фильтр |
129
|
|
|
* @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html |
130
|
|
|
* @return self $this |
131
|
|
|
*/ |
132
|
|
View Code Duplication |
public function addNotFilter($type, $filter) |
|
|
|
|
133
|
|
|
{ |
134
|
|
|
if (!isset($this->params['body']['query']['bool']['must_not'])) { |
135
|
|
|
$this->params['body']['query']['bool']['must_not'] = []; |
136
|
|
|
} |
137
|
|
|
$this->params['body']['query']['bool']['must_not'][] = [$type => $filter]; |
138
|
|
|
return $this; |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* Создать фильтр. |
144
|
|
|
* |
145
|
|
|
* @param $field - поле по которому фильтруем (id, page.categoryId...) |
146
|
|
|
* @example $query->where('channel')->equal(1)->where('page.categoryId')->in([10,12]); |
147
|
|
|
* @return Where; |
|
|
|
|
148
|
|
|
*/ |
149
|
|
|
public function where($field) |
150
|
|
|
{ |
151
|
|
|
if (null === $this->whereHelper) { |
152
|
|
|
$this->whereHelper = new Where($this); |
153
|
|
|
} |
154
|
|
|
$this->whereHelper->setField($field); |
155
|
|
|
return $this->whereHelper; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* Добавить в фильтр сложное условие с вычислениями, на скриптовом языке painless или groovy. |
161
|
|
|
* Использование параметров рекомендуется, для увеличения производительности и эффективности компилирования скриптов. |
162
|
|
|
* |
163
|
|
|
* @param Script $script - скрипт |
164
|
|
|
* @return self $this; |
165
|
|
|
* @link https://www.elastic.co/guide/en/elasticsearch/reference/5.0/query-dsl-script-query.html |
166
|
|
|
* @link https://www.elastic.co/guide/en/elasticsearch/reference/5.0/modules-scripting-painless.html |
167
|
|
|
*/ |
168
|
|
|
public function whereScript(Script $script) |
169
|
|
|
{ |
170
|
|
|
$this->addFilter('script', $script->compile()); |
171
|
|
|
return $this; |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* Установить поле сортировки. |
177
|
|
|
* Для сортировки по релевантности существует псевдополе _score (значение больше - релевантность лучше) |
178
|
|
|
* @param $field - поле сортировки |
179
|
|
|
* @param string $order - направление сортировки asc|desc |
180
|
|
|
* @example $query->setOrderBy('_score', 'desc'); |
181
|
|
|
* @return self $this |
182
|
|
|
*/ |
183
|
|
|
public function setOrderBy($field, $order = 'asc') |
184
|
|
|
{ |
185
|
|
|
$this->params['body']['sort'] = []; |
186
|
|
|
$this->addOrderBy($field, $order); |
187
|
|
|
return $this; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* Добавить поле сортировки. |
192
|
|
|
* Для сортировки по релевантности существует псевдополе _score (значение больше - релевантность лучше) |
193
|
|
|
* @param $field - поле сортировки |
194
|
|
|
* @param string $order - направление сортировки asc|desc |
195
|
|
|
* @example $query->addOrderBy('_score', 'desc'); |
196
|
|
|
* @example $query->addOrderBy('seller.rating', 'desc'); |
197
|
|
|
* @return self $this |
198
|
|
|
*/ |
199
|
|
|
public function addOrderBy($field, $order = 'asc') |
200
|
|
|
{ |
201
|
|
|
$field = (string) $field; |
202
|
|
|
$order = (string) $order; |
203
|
|
|
if (!isset($this->params['body']['sort'])) { |
204
|
|
|
$this->params['body']['sort'] = []; |
205
|
|
|
} |
206
|
|
|
$this->params['body']['sort'][] = [$field => ['order' => $order]]; |
207
|
|
|
return $this; |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* Установить лимиты выборки |
213
|
|
|
* @param $limit - сколько строк выбирать |
214
|
|
|
* @param int $offset - сколько строк пропустить |
215
|
|
|
* @return self $this; |
216
|
|
|
*/ |
217
|
|
|
public function limit($limit, $offset = 0) |
218
|
|
|
{ |
219
|
|
|
$this->params['body']['size'] = (int) $limit; |
220
|
|
|
$this->params['body']['from'] = (int) $offset; |
221
|
|
|
return $this; |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
/** |
225
|
|
|
* Получить собранный запрос |
226
|
|
|
* @return array |
227
|
|
|
*/ |
228
|
|
|
public function getQuery() |
229
|
|
|
{ |
230
|
|
|
$params = $this->params; |
231
|
|
|
|
232
|
|
|
if (!isset($params['body']['_source'])) { |
233
|
|
|
$params['body']['_source'] = true; |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
return $params; |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
protected function executeQuery(array $query) |
240
|
|
|
{ |
241
|
|
|
return $this->elastic->search($query); |
|
|
|
|
242
|
|
|
} |
243
|
|
|
} |
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.