/** * Migrate a new version of an index. * * @param \Phroggyy\Discover\Contracts\Searchable $model * @param int $version * @param array $properties * @param int $shards * @param int $replicas */ public function migrateIndex(Searchable $model, int $version, array $properties, $shards = 2, $replicas = 1) { $client = app(Client::class); $alias = $model->getSearchIndex(); $type = $model->getSearchType(); $index = $alias . '-' . $version; $currentIndex = $alias . '-' . $version - 1; $description = ['index' => $index, 'body' => ['settings' => ['index' => ['number_of_shards' => $shards, 'number_of_replicas' => $replicas]], 'mappings' => [$type => ['properties' => $properties]]]]; $client->indices()->create($description); // Reindex the existing data if we're migrating if ($version > 1) { $timestamp = null; while (true) { if ($timestamp) { $query = ['filtered' => ['query' => ['match_all' => []], 'filter' => ['range' => ['created_at' => ['gte' => $timestamp]]]]]; } else { $query = ['match_all' => []]; } $timestamp = Carbon::now()->format('Y-m-d H:i:s'); $search = $client->search(['search_type' => 'scan', 'scroll' => '1m', 'size' => 1000, 'index' => $currentIndex, 'sort' => ['_doc'], 'body' => ['query' => [$query]]]); $scrollId = $search['_scroll_id']; while (true) { $response = $client->scroll(['scroll_id' => $scrollId, 'scroll' => '1m']); if (!count($response['hits']['hits'])) { break; } $scrollId = $response['_scroll_id']; $results = array_map(function ($result) { return ['create' => $result['_source']]; }, $response['hits']['hits']); $client->bulk(['index' => $index, 'type' => $type, 'body' => $results]); } if ($scrollId == $search['_scroll_id']) { break; } } $client->indices()->deleteAlias(['index' => $currentIndex, 'name' => $alias]); } $client->indices()->putAlias(['index' => $index, 'name' => $alias]); }
/** * Structure the matches array. * * @param \Phroggyy\Discover\Contracts\Searchable $model * @param array $query * @return array|string */ private function structureMatches(Searchable $model, $query) { // If the query is an array of arrays, we assume the // developer knows exactly what they're doing and // are providing a complete match query for us. if (is_array($query) && !Arr::isAssoc($query)) { return $query; } $key = ''; // If the search index turns out to actually be nested, we // want to make sure we use the name of the subdocument // when such a query is performed. This is necessary. if ($this->indexIsNested($model->getSearchIndex())) { $key = $this->retrieveNestedIndex($model->getSearchIndex())[1] . '.'; } // If the query is just a string, we assume the user // intends to just do a simple match query on the // default search field defined in their model. if (is_string($query)) { return [['match' => [$key . $model->getDefaultSearchField() => $query]]]; } $query = Collection::make($query); return $query->map(function ($constraint, $property) use($key) { if (strpos($property, '.') === false) { $property = $key . $property; } return ['match' => [$property => $constraint]]; })->values()->all(); }