1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Alhoqbani\Elastic; |
4
|
|
|
|
5
|
|
|
use Elasticsearch\Client; |
6
|
|
|
use Illuminate\Database\Eloquent\Collection; |
7
|
|
|
use Illuminate\Support\Arr; |
8
|
|
|
use Laravel\Scout\Builder; |
9
|
|
|
use Laravel\Scout\Engines\Engine; |
10
|
|
|
|
11
|
|
|
class ScoutElasticEngine extends Engine |
12
|
|
|
{ |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* The Elasticsearch client. |
16
|
|
|
* |
17
|
|
|
* @var \Elasticsearch\Client |
18
|
|
|
*/ |
19
|
|
|
private $client; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* ElasticSearchScoutEngine constructor. |
23
|
|
|
* |
24
|
|
|
* @param \Elasticsearch\Client $client |
25
|
|
|
*/ |
26
|
|
|
public function __construct(Client $client) |
27
|
|
|
{ |
28
|
|
|
$this->client = $client; |
29
|
|
|
} |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Update the given model in the index. |
33
|
|
|
* |
34
|
|
|
* @param \Illuminate\Database\Eloquent\Collection $models |
35
|
|
|
* |
36
|
|
|
* @return void |
37
|
|
|
*/ |
38
|
|
|
public function update($models) |
39
|
|
|
{ |
40
|
|
|
$index = $models->first()->searchableAs(); |
41
|
|
|
|
42
|
|
|
$params = ['body' => []]; |
43
|
|
|
foreach ($models as $model) { |
44
|
|
|
$array = $model->toSearchableArray(); |
45
|
|
|
|
46
|
|
|
if (empty($array)) { |
47
|
|
|
return; |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
$params['body'][] = [ |
51
|
|
|
'index' => [ |
52
|
|
|
'_index' => $index, |
53
|
|
|
'_type' => $index, |
54
|
|
|
'_id' => $model->getKey(), |
55
|
|
|
], |
56
|
|
|
]; |
57
|
|
|
$params['body'][] = $array; |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
$this->client->bulk($params); |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Remove the given model from the index. |
65
|
|
|
* |
66
|
|
|
* @param \Illuminate\Database\Eloquent\Collection $models |
67
|
|
|
* |
68
|
|
|
* @return void |
69
|
|
|
*/ |
70
|
|
|
public function delete($models) |
71
|
|
|
{ |
72
|
|
|
$index = $models->first()->searchableAs(); |
73
|
|
|
|
74
|
|
|
$params = ['body' => []]; |
75
|
|
|
foreach ($models as $model) { |
76
|
|
|
$params['body'][] = [ |
77
|
|
|
'delete' => [ |
78
|
|
|
'_index' => $index, |
79
|
|
|
'_type' => $index, |
80
|
|
|
'_id' => $model->getKey(), |
81
|
|
|
], |
82
|
|
|
]; |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
$this->client->bulk($params); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* Perform the given search on the engine. |
90
|
|
|
* |
91
|
|
|
* @param \Laravel\Scout\Builder $builder |
92
|
|
|
* |
93
|
|
|
* @return mixed |
94
|
|
|
*/ |
95
|
|
|
public function search(Builder $builder) |
96
|
|
|
{ |
97
|
|
|
$params = $this->prepareParams($builder); |
98
|
|
|
|
99
|
|
|
return $this->client->search($params); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Perform the given search on the engine. |
104
|
|
|
* |
105
|
|
|
* @param \Laravel\Scout\Builder $builder |
106
|
|
|
* @param int $perPage |
107
|
|
|
* @param int $page |
108
|
|
|
* |
109
|
|
|
* @return mixed |
110
|
|
|
*/ |
111
|
|
|
public function paginate(Builder $builder, $perPage, $page) |
112
|
|
|
{ |
113
|
|
|
$params = $this->prepareParams($builder); |
114
|
|
|
|
115
|
|
|
$params['size'] = $perPage; |
116
|
|
|
$params['from'] = ($page - 1) * $perPage; |
117
|
|
|
unset($params['body']['size'], $params['body']['from']); |
118
|
|
|
|
119
|
|
|
return $this->client->search($params); |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Pluck and return the primary keys of the given results. |
124
|
|
|
* |
125
|
|
|
* @param mixed $results |
126
|
|
|
* |
127
|
|
|
* @return \Illuminate\Support\Collection |
128
|
|
|
*/ |
129
|
|
|
public function mapIds($results) |
130
|
|
|
{ |
131
|
|
|
return collect($results['hits']['hits'])->pluck('_id')->values(); |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* Map the given results to instances of the given model. |
136
|
|
|
* |
137
|
|
|
* @param mixed $results |
138
|
|
|
* @param \Illuminate\Database\Eloquent\Model $model |
139
|
|
|
* |
140
|
|
|
* @return \Illuminate\Database\Eloquent\Collection |
141
|
|
|
*/ |
142
|
|
|
public function map($results, $model) |
143
|
|
|
{ |
144
|
|
|
if ($results['hits']['total'] === 0) { |
145
|
|
|
return Collection::make(); |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
$keys = collect($results['hits']['hits']) |
149
|
|
|
->pluck('_id')->values()->all(); |
150
|
|
|
|
151
|
|
|
$models = $model->whereIn( |
152
|
|
|
$model->getQualifiedKeyName(), |
153
|
|
|
$keys |
154
|
|
|
)->get()->keyBy($model->getKeyName()); |
155
|
|
|
|
156
|
|
|
return Collection::make($results['hits']['hits'])->map(function ($hit) use ($model, $models) { |
157
|
|
|
$key = $hit['_id']; |
158
|
|
|
|
159
|
|
|
if (isset($models[$key])) { |
160
|
|
|
return $models[$key]; |
161
|
|
|
} |
162
|
|
|
})->filter()->values(); |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* Get the total count from a raw result returned by the engine. |
167
|
|
|
* |
168
|
|
|
* @param mixed $results |
169
|
|
|
* |
170
|
|
|
* @return int |
171
|
|
|
*/ |
172
|
|
|
public function getTotalCount($results) |
173
|
|
|
{ |
174
|
|
|
return $results['hits']['total']; |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* Parse and prepare the params to send to Elasticsearch client |
179
|
|
|
* |
180
|
|
|
* @param \Laravel\Scout\Builder $builder |
181
|
|
|
* |
182
|
|
|
* @return array |
183
|
|
|
*/ |
184
|
|
|
protected function prepareParams(Builder $builder) |
185
|
|
|
{ |
186
|
|
|
$params = [ |
187
|
|
|
'index' => $builder->index ?? $builder->model->searchableAs(), |
188
|
|
|
// 'type' => $builder->index ?? $builder->model->searchableAs(), |
|
|
|
|
189
|
|
|
'size' => $builder->limit ?? $builder->model->getPerPage(), |
190
|
|
|
'body' => [ |
191
|
|
|
'query' => [ |
192
|
|
|
'multi_match' => [ |
193
|
|
|
'query' => $builder->query, |
194
|
|
|
'fields' => '_all', |
195
|
|
|
], |
196
|
|
|
], |
197
|
|
|
], |
198
|
|
|
]; |
199
|
|
|
|
200
|
|
|
if ($builder->callback) { |
201
|
|
|
$params = array_merge($params, |
202
|
|
|
call_user_func( |
203
|
|
|
$builder->callback, |
204
|
|
|
$this->client, |
205
|
|
|
$builder->query |
206
|
|
|
)); |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
return $params; |
210
|
|
|
} |
211
|
|
|
} |
212
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.