/** * Scan directories for Eloquent models that use the SearchableTrait. * Generate paths for all these models so that we can (re)index these * models. * * @return void */ public function fire() { $models = $this->argument('model'); foreach ($models as $model) { $this->compilePaths(new $model()); } if ($directories = $this->option('dir')) { $directoryModels = array_diff(Utils::findSearchableModels($directories), $models); foreach ($directoryModels as $model) { // Find paths for related models $this->compilePaths(new $model()); } } if (!empty($models) || !empty($directoryModels)) { $this->writeConfig(); } else { $this->info('No models found.'); } }
/** * Execute the console command. * * @return mixed */ public function fire() { $directoryModels = []; $models = $this->argument('model'); foreach ($models as $model) { $instance = $this->getModelInstance($model); $this->reindexModel($instance); } if ($directories = $this->option('dir')) { $directoryModels = array_diff(Utils::findSearchableModels($directories), $models); foreach ($directoryModels as $model) { $instance = $this->getModelInstance($model); $this->reindexModel($instance); } } if (empty($models) && empty($directoryModels)) { $this->info('No models found.'); } }
/** * Initialize the default index settings and mappings * * @return array */ private function getDefaultIndexParams() { $analyzers = self::$config->get('elasticsearch.analyzers'); $params = self::$config->get('elasticsearch.defaults.index'); $mapping = []; $mapping_options = array_combine($analyzers, array_map(function ($type) { $config = $this->getProxy()->getConfig(); // Maintain backwards compatibility by allowing a plain array of analyzer => fields $field_mappings = Utils::findKey($config, $type, false) ?: []; // Also read from a dedicated array key called 'analyzers' if (isset($config['analyzers'])) { $field_mappings = array_merge($field_mappings, Utils::findKey($config['analyzers'], $type, false) ?: []); } return $field_mappings; }, $analyzers)); foreach (array_unique(array_flatten(array_values($mapping_options))) as $field) { // Extract path segments from dot separated field $pathSegments = explode('.', $field); // Last element is the field name $fieldName = array_pop($pathSegments); // Apply default field mapping $fieldMapping = ['type' => "multi_field", 'fields' => [$fieldName => ['type' => 'string', 'index' => 'not_analyzed'], 'analyzed' => ['type' => 'string', 'index' => 'analyzed']]]; // Check if we need to add additional mappings foreach ($mapping_options as $type => $fields) { if (in_array($field, $fields)) { $fieldMapping['fields'][$type] = ['type' => 'string', 'index' => 'analyzed', 'analyzer' => "flexible_{$type}_index"]; } } if (!empty($pathSegments)) { $mapping = Utils::array_merge_recursive_distinct($mapping, $this->getNestedFieldMapping($fieldName, $fieldMapping, $pathSegments)); } else { $mapping[$fieldName] = $fieldMapping; } } if (!empty($mapping)) { $params['mappings']['_default_']['properties'] = $mapping; } $params['index'] = $this->getName(); $params['type'] = $this->getProxy()->getType(); return $params; }
/** * Construct the payload from the options */ private function getPayload() { $payloads = ['json' => Utils::findKey($this->options, 'json', false), 'query' => Utils::findKey($this->options, 'query', false), 'similar' => ['query' => ['more_like_this' => ['fields' => $this->fields, 'like_text' => $this->term, 'min_doc_freq' => 1, 'min_term_freq' => 1, 'analyzer' => "flexible_search2"]]], 'autocomplete' => ['query' => ['multi_match' => ['fields' => $this->fields, 'query' => $this->term, 'analyzer' => "flexible_autocomplete_search"]]]]; // Find the correct payload based on the options $payload_key = array_intersect_key($this->options, $payloads); $operator = Utils::findKey($this->options, 'operator', 'and'); if (count($payload_key) == 1) { $this->payload = array_merge($this->payload, $payloads[key($payload_key)]); } elseif (count($payload_key) == 0) { if ($this->term == '*') { $payload = ['match_all' => []]; } else { $queries = []; foreach ($this->fields as $field) { $qs = []; $shared_options = ['query' => $this->term, 'operator' => $operator, 'boost' => 1]; if ($field == '_all' || substr_compare($field, '.analyzed', -9, 9) === 0) { $qs = array_merge($qs, [array_merge($shared_options, ['boost' => 10, 'analyzer' => "flexible_search"]), array_merge($shared_options, ['boost' => 10, 'analyzer' => "flexible_search2"])]); if ($misspellings = Utils::findKey($this->options, 'misspellings', false)) { $distance = 1; $qs = array_merge($qs, [array_merge($shared_options, ['fuzziness' => $distance, 'max_expansions' => 3, 'analyzer' => "flexible_search"]), array_merge($shared_options, ['fuzziness' => $distance, 'max_expansions' => 3, 'analyzer' => "flexible_search2"])]); } } elseif (substr_compare($field, '.exact', -6, 6) === 0) { $f = substr($field, 0, -6); $queries[] = ['match' => [$f => array_merge($shared_options, ['analyzer' => 'keyword'])]]; } else { $analyzer = preg_match('/\\.word_(start|middle|end)\\z/', $field) ? "flexible_word_search" : "flexible_autocomplete_search"; $qs[] = array_merge($shared_options, ['analyzer' => $analyzer]); } $queries = array_merge($queries, array_map(function ($q) use($field) { return ['match' => [$field => $q]]; }, $qs)); } $payload = ['dis_max' => ['queries' => $queries]]; } $this->payload['query'] = $payload; } else { // We have multiple query definitions, so abort throw new \InvalidArgumentException('Cannot use multiple query definitions.'); } if ($load = Utils::findKey($this->options, 'load', false)) { $this->payload['fields'] = is_array($load) ? $load : []; } elseif ($select = Utils::findKey($this->options, 'select', false)) { $this->payload['fields'] = $select; } }