elastic = $elastic; $this->logger = new Logger('elastic'); $this->logger->pushHandler(new StreamHandler(storage_path('logs/elasticsearch/error.log'), Logger::ERROR)); } /** * Update the given model in the index. * * @param \Illuminate\Database\Eloquent\Collection $models * @return void */ public function update($models) { $params['body'] = []; $models->each(function ($model) use (&$params) { $params['body'][] = [ 'update' => [ '_id' => $model->getKey(), '_index' => $model->searchableAs(), '_type' => $this->type, ] ]; $params['body'][] = [ 'doc' => $model->toSearchableArray(), 'doc_as_upsert' => true ]; }); $result=$this->elastic->bulk($params); if ($result['errors'] === true) { $this->logger->error("更新失败", $result); //throw new \Exception(json_encode($result)); } } /** * Remove the given model from the index. * * @param \Illuminate\Database\Eloquent\Collection $models * @return void */ public function delete($models) { $params['body'] = []; $models->each(function ($model) use (&$params) { $params['body'][] = [ 'delete' => [ '_id' => $model->getKey(), '_index' => $model->searchableAs(), '_type' => $this->type, ] ]; }); $this->elastic->bulk($params); } /** * Perform the given search on the engine. * * @param \Laravel\Scout\Builder $builder * @return mixed */ public function search(Builder $builder) { return $this->performSearch($builder, array_filter([ 'size' => $builder->limit, ])); } /** * Perform the given search on the engine. * * @param \Laravel\Scout\Builder $builder * @param int $perPage * @param int $page * @return mixed */ public function paginate(Builder $builder, $perPage, $page) { $result = $this->performSearch($builder, [ 'from' => (($page * $perPage) - $perPage), 'size' => $perPage, ]); return $result; } /** * Pluck and return the primary keys of the given results. * * @param mixed $results * @return \Illuminate\Support\Collection */ public function mapIds($results) { return collect($results['hits']['hits'])->pluck('_id')->values(); } /** * Map the given results to instances of the given model. * * @param \Laravel\Scout\Builder $builder * @param mixed $results * @param \Illuminate\Database\Eloquent\Model $model * @return \Illuminate\Database\Eloquent\Collection */ public function map(Builder $builder, $results, $model) { if ($results['hits']['total'] === 0) { return Collection::make(); } $keys = collect($results['hits']['hits']) ->pluck('_id')->values()->all(); $models = $model->getScoutModelsByIds($builder, $keys)->keyBy(function ($model) { return $model->getScoutKey(); }); return collect($results['hits']['hits'])->map(function ($hit) use ($model, $models) { return isset($models[$hit['_id']]) ? $models[$hit['_id']] : null; })->filter()->values(); } /** * Get the total count from a raw result returned by the engine. * * @param mixed $results * @return int */ public function getTotalCount($results) { return $results['hits']['total']>1000?1000:$results['hits']['total']; } /** * Flush all of the model's records from the engine. * * @param \Illuminate\Database\Eloquent\Model $model * @return void */ public function flush($model) { // TODO: Implement flush() method. } /** * Perform the given search on the engine. * * @param ElasticsearchBuilder $builder * @param array $options * @return mixed */ protected function performSearch($builder, array $options = []) { $params = [ 'index' => $builder->model->searchableAs(), 'type' => $this->type, 'body' => [ 'query' => [ 'bool' => [ ] ] ] ]; if (!empty($query = $builder->getQueryData())) { $params['body']['query']['bool']=$query; } $relation_sotr=[]; if (!empty($builder->query)) { $relation_sotr[]=['_score' => 'desc']; $params['body']['query']['bool']['must'][]=[ 'bool'=>[ "should"=>[ [ 'match' => [ 'search_field1' => [ "query" => "{$builder->query}", "boost" => 2 ] ] ], [ 'match' => [ 'search_field2' => [ "query" => "{$builder->query}", "boost" => 0 ] ] ] ] ] ]; } if (empty($params['body']['query']['bool'])) { $params['body']['query']['bool']['must'][]=['match_all'=>new \ArrayObject()]; } if ($sort = $this->sort($builder)) { if (!empty($relation_sotr)) { $sort =array_merge($relation_sotr, $sort); } $params['body']['sort'] = $sort; } if (isset($options['from'])) { $params['body']['from'] = $options['from']; } if (isset($options['size'])) { $params['body']['size'] = $options['size']; } if ($builder->callback) { return call_user_func( $builder->callback, $this->elastic, $builder->query, $params ); } return $this->elastic->search($params); } /** * Generates the sort if theres any. * * @param Builder $builder * @return array|null */ protected function sort($builder) { if (count($builder->orders) == 0) { return null; } return collect($builder->orders)->map(function ($order) { if (is_array($order['column'])) { return ['_geo_distance'=> $order['column']]; } return [$order['column'] => $order['direction']]; })->toArray(); } }