Passed
Push — master ( 1e3586...cfacb5 )
by
unknown
02:48 queued 12s
created

Search::facet()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 9
nc 8
nop 3
dl 0
loc 15
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
4
namespace Manticoresearch;
5
6
use Manticoresearch\Query\BoolQuery;
7
use Manticoresearch\Query\Distance;
8
use Manticoresearch\Query\Equals;
9
use Manticoresearch\Query\In;
10
use Manticoresearch\Query\MatchQuery;
11
use Manticoresearch\Query\MatchPhrase;
12
use Manticoresearch\Query\QueryString;
13
use Manticoresearch\Query\Range;
14
use Manticoresearch\Query\ScriptFields;
15
16
/**
17
 * Manticore search object
18
 * @category ManticoreSearch
19
 * @package ManticoreSearch
20
 * @author Adrian Nuta <[email protected]>
21
 * @link https://manticoresearch.com
22
 */
23
class Search
24
{
25
    const FILTER_AND = "AND";
26
    const FILTER_OR = "OR";
27
    const FILTER_NOT = "NOT";
28
29
    /**
30
     * @var Client
31
     */
32
    protected $client;
33
34
    protected $query;
35
    protected $body;
36
    /**
37
     * @var array
38
     */
39
    protected $params = [];
40
41
    protected static $replaceOperator = [
42
        '=' => 'equals',
43
        '>=' => 'gte',
44
        '>' => 'gt',
45
        '<' => 'lt',
46
        '<=' => 'lte',
47
    ];
48
49
    public function __construct(Client $client)
50
    {
51
        $this->client = $client;
52
        $this->query = new BoolQuery();
53
    }
54
55
    public function setIndex($index): self
56
    {
57
        $this->params['index'] = $index;
58
        return $this;
59
    }
60
61
    public function setSource($source): self
62
    {
63
        $this->params['_source'] = $source;
64
        return $this;
65
    }
66
67
    /**
68
     * @param string $queryString
69
     * @return $this
70
     */
71
    public function search($queryString): self
72
    {
73
        if (is_object($queryString)) {
0 ignored issues
show
introduced by
The condition is_object($queryString) is always false.
Loading history...
74
            $this->query = $queryString;
75
            return $this;
76
        }
77
        $this->query->must(new QueryString($queryString));
78
        return $this;
79
    }
80
81
    public function match($keywords, $fields = null): self
82
    {
83
        $f = "*";
84
        if ($fields !== null && is_string($fields)) {
85
            $f = $fields;
86
        }
87
        $this->query->must(new MatchQuery($keywords, $f));
88
        return $this;
89
    }
90
91
    public function phrase($string, $fields = null): self
92
    {
93
        $f = "*";
94
        if ($fields !== null && is_string($fields)) {
95
            $f = $fields;
96
        }
97
        $this->query->must(new MatchPhrase($string, $f));
98
        return $this;
99
    }
100
101
    public function limit($limit): self
102
    {
103
        $this->params['limit'] = $limit;
104
        return $this;
105
    }
106
107
    /**
108
     * @param string $name
109
     * @param string $exp
110
     * @return $this
111
     */
112
    public function expression($name, $exp): self
113
    {
114
        if (!isset($this->params['script_fields'])) {
115
            $this->params['script_fields'] = new ScriptFields();
116
        }
117
        $this->params['script_fields']->add($name, $exp);
118
        return $this;
119
    }
120
121
    public function highlight($fields = [], $settings = []): self
122
    {
123
124
        if (count($fields) === 0 && count($settings)===0) {
125
            $this->params['highlight'] =  new \stdClass();
126
            return $this;
127
        }
128
        $this->params['highlight'] = [];
129
        if (count($fields) > 0) {
130
            $this->params['highlight']['fields'] =$fields;
131
        }
132
        if (count($settings)>0) {
133
            foreach ($settings as $name => $value) {
134
                $this->params['highlight'][$name] =$value;
135
            }
136
        }
137
        return $this;
138
    }
139
140
    public function distance($args): self
141
    {
142
        $this->query->must(new Distance($args));
143
        return $this;
144
    }
145
146
    protected function getAttrObject($attr, $op, $values)
147
    {
148
        $op = static::$replaceOperator[$op] ?? $op;
149
150
        switch ($op) {
151
            case 'range':
152
                $object = new Range($attr, [
153
                    'gte' => $values[0],
154
                    'lte' => $values[1]
155
                ]);
156
                break;
157
            case 'lt':
158
            case 'lte':
159
            case 'gt':
160
            case 'gte':
161
                $object = new Range($attr, [
162
                    $op => $values[0],
163
                ]);
164
                break;
165
            case 'in':
166
                $object = new In($attr, $values);
167
                break;
168
            case 'equals':
169
                $object = new Equals($attr, $values[0]);
170
                break;
171
            default:
172
                $object = null;
173
        }
174
175
        return $object;
176
    }
177
178
    public function filter($attr, $op = null, $values = null, $boolean = self::FILTER_AND): self
179
    {
180
        if (!is_object($attr)) {
181
            if (is_null($values)) {
182
                $values = $op;
183
                $op = "equals";
184
            }
185
186
            if (!is_array($values)) {
187
                $values = [$values];
188
            }
189
190
            $attr = $this->getAttrObject($attr, $op, $values);
191
192
            if (!$attr) {
193
                return $this;
194
            }
195
        }
196
197
        if ($boolean === self::FILTER_AND) {
198
            $this->query->must($attr);
199
        } elseif ($boolean === self::FILTER_OR) {
200
            $this->query->should($attr);
201
        } elseif ($boolean === self::FILTER_NOT) {
202
            $this->query->mustNot($attr);
203
        }
204
205
        return $this;
206
    }
207
208
    public function orFilter($attr, $op = null, $values = null): self
209
    {
210
        return $this->filter($attr, $op, $values, self::FILTER_OR);
211
    }
212
213
    public function notFilter($attr, $op = null, $values = null): self
214
    {
215
        return $this->filter($attr, $op, $values, self::FILTER_NOT);
216
    }
217
218
    public function offset($offset): self
219
    {
220
        $this->params['offset'] = $offset;
221
        return $this;
222
    }
223
224
    public function maxMatches($maxmatches): self
225
    {
226
        $this->params['max_matches'] = $maxmatches;
227
        return $this;
228
    }
229
230
    public function facet($field, $group = null, $limit = null) : self
231
    {
232
        // reset facets
233
        if ($field === false) {
234
            $this->params['aggs'] = [];
235
        }
236
        if ($group === null) {
237
            $group = $field;
238
        }
239
        $terms = ['field'=>$field];
240
        if ($limit !==null) {
241
            $terms['size'] = $limit;
242
        }
243
        $this->params['aggs'][$group] =['terms' =>$terms];
244
        return $this;
245
    }
246
247
    public function sort($field, $direction = 'asc', $mode = null): self
248
    {
249
        // reset sorting
250
        if ($field === false) {
251
            $this->params['sort'] = [];
252
        }
253
        //if 1st arg is array means we have a sorting expression
254
        if (is_array($field)) {
255
            //is 2nd arg is true we full set the sort with the expr, otherwise just add it
256
            if (isset($direction) && $direction === true) {
257
                $this->params['sort'] = $field;
258
            } else {
259
                $this->params['sort'] [] = $field;
260
            }
261
            return $this;
262
        }
263
        if (!isset($this->params['sort'])) {
264
            $this->params['sort'] = [];
265
        }
266
        if ($mode === null) {
267
            $this->params['sort'] [] = [$field => $direction];
268
        } else {
269
            $this->params['sort'] [] = [$field => ['order' => $direction, 'mode' => $mode]];
270
        }
271
272
        return $this;
273
    }
274
275
    public function option($name, $value): self
276
    {
277
        if (is_null($value)) {
278
            unset($this->params['options'][$name]);
279
        } else {
280
            $this->params['options'][$name] = $value;
281
        }
282
283
        return $this;
284
    }
285
286
    public function profile(): self
287
    {
288
        $this->params['profile'] = true;
289
        return $this;
290
    }
291
292
    /**
293
     * @return ResultSet
294
     */
295
    public function get()
296
    {
297
        $this->body = $this->compile();
298
        $resp = $this->client->search(['body' => $this->body], true);
299
        return new ResultSet($resp);
300
    }
301
302
    public function compile()
303
    {
304
        $body = $this->params;
305
        $query = $this->query->toArray();
306
        if ($query !== null) {
307
            $body['query'] = $query;
308
        }
309
310
        if (isset($this->params['script_fields'])) {
311
            $body['script_fields'] = $this->params['script_fields']->toArray();
312
            unset($this->params['script_fields']);
313
        }
314
315
        return $body;
316
    }
317
318
    public function getBody()
319
    {
320
        return $this->body;
321
    }
322
323
    public function reset()
324
    {
325
        $this->params = [];
326
        $this->query = new BoolQuery();
327
    }
328
329
    public function getClient()
330
    {
331
        return $this->client;
332
    }
333
}
334