diff --git a/src/AggregateRule.php b/src/AggregateRule.php new file mode 100644 index 0000000..331199b --- /dev/null +++ b/src/AggregateRule.php @@ -0,0 +1,10 @@ +wheres['must'][] = ['term' => ['__soft_deleted' => 1]]; }); } + + /** + * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/returning-only-agg-results.html + * + * @param int $size + * @return $this + */ + public function aggregate($size = 0) + { + $this->take($size); + $payloadCollection = []; + $aggregateRules = $this->aggregateRules ?: $this->model->getAggregateRules(); + foreach ($aggregateRules as $rule) { + if (is_callable($rule)) { + $payloadCollection[] = call_user_func($rule); + } else { + $ruleEntity = new $rule; + if ($aggregatePayload = $ruleEntity->buildAggregatePayload()) { + $payloadCollection[] = $aggregatePayload; + } + } + } + $this->aggregates = array_reduce($payloadCollection, 'array_merge', []); + return $this->engine()->search($this); + } + + /** + * Adds rule to the aggregate rules of the builder. + * + * @param $rule + * @return $this + */ + public function aggregateRule($rule) + { + $this->aggregateRules[] = $rule; + return $this; + } } diff --git a/src/ElasticEngine.php b/src/ElasticEngine.php index 235e6a7..4ad348d 100644 --- a/src/ElasticEngine.php +++ b/src/ElasticEngine.php @@ -136,6 +136,7 @@ public function buildSearchQueryPayloadCollection(Builder $builder, array $optio ->setIfNotEmpty('body._source', $builder->select) ->setIfNotEmpty('body.collapse.field', $builder->collapse) ->setIfNotEmpty('body.sort', $builder->orders) + ->setIfNotEmpty('body.aggs', $builder->aggregates) ->setIfNotEmpty('body.explain', $options['explain'] ?? null) ->setIfNotEmpty('body.profile', $options['profile'] ?? null) ->setIfNotNull('body.from', $builder->offset) @@ -305,7 +306,10 @@ public function map(Builder $builder, $results, $model) $columns[] = $scoutKeyName; } - $ids = $this->mapIds($results)->all(); + $ids = []; + foreach ($results['hits']['hits'] as $hit) { + $ids[] = $hit['_source'][$scoutKeyName]; + } $query = $model::usesSoftDelete() ? $model->withTrashed() : $model->newQuery(); @@ -315,8 +319,8 @@ public function map(Builder $builder, $results, $model) ->keyBy($scoutKeyName); return Collection::make($results['hits']['hits']) - ->map(function ($hit) use ($models) { - $id = $hit['_id']; + ->map(function ($hit) use ($models, $scoutKeyName) { + $id = $hit['_source'][$scoutKeyName]; if (isset($models[$id])) { $model = $models[$id]; diff --git a/src/Indexers/SingleIndexer.php b/src/Indexers/SingleIndexer.php index e17fdeb..40091a9 100644 --- a/src/Indexers/SingleIndexer.php +++ b/src/Indexers/SingleIndexer.php @@ -52,10 +52,13 @@ public function delete(Collection $models) { $models->each(function ($model) { $payload = (new DocumentPayload($model)) - ->set('client.ignore', 404) - ->get(); + ->set('client.ignore', 404); - ElasticClient::delete($payload); + if ($documentRefresh = config('scout_elastic.document_refresh')) { + $payload->set('refresh', $documentRefresh); + } + + ElasticClient::delete($payload->get()); }); } } diff --git a/src/Searchable.php b/src/Searchable.php index c52064d..c832fc8 100644 --- a/src/Searchable.php +++ b/src/Searchable.php @@ -97,6 +97,14 @@ public function getSearchRules() $this->searchRules : [SearchRule::class]; } + /** + * @return array + */ + public function getAggregateRules() + { + return isset($this->aggregateRules) && count($this->aggregateRules) > 0 ? $this->aggregateRules : [AggregateRule::class]; + } + /** * Execute the search. *