/** * Create new ES field mappings for the given fields from the configuration * TODO align callback names with Config::names so we can simply call this method with the kind string * @param array $config_fields * @param string $kind of internal fields: meta|field|taxonomy used to call the right indexer_map filter */ static function _map_values($config_fields, $kind) { $index = self::_index(false); $numeric = Config::option('numeric'); $notanalyzed = Config::option('not_analyzed'); foreach ($config_fields as $field) { // set default $props = array('type' => 'string'); // detect special field type if (isset($numeric[$field])) { $props['type'] = 'float'; } elseif (isset($notanalyzed[$field]) || $kind == 'taxonomy') { $props['index'] = 'not_analyzed'; } elseif ($field == 'post_date') { $props['type'] = 'date'; $props['format'] = 'date_time_no_millis'; } else { $props['index'] = 'analyzed'; } if ($props['type'] == 'string' && $props['index'] == 'analyzed') { // provides more accurate searches // TODO: assumes plugin users are in english $lang = Config::apply_filters('string_language', 'english'); $props = array('type' => 'multi_field', 'fields' => array($field => $props, $lang => array_merge($props, array('analyzer' => $lang)))); } // generic filter indexer_map_field| indexer_map_meta | indexer_map_taxonomy $props = Config::apply_filters('indexer_map_' . $kind, $props, $field); // also index taxonomy_name field if ($kind == 'taxonomy') { $tax_name_props = array('type' => 'string'); $tax_name_props = Config::apply_filters('indexer_map_taxonomy_name', $tax_name_props, $field); } foreach (Config::types() as $type) { $type = $index->getType($type); $mapping = new \Elastica\Type\Mapping($type); $mapping->setProperties(array($field => $props)); $mapping->send(); // second mapping for taxonomy_name if (isset($tax_name_props)) { $mapping = new \Elastica\Type\Mapping($type); $mapping->setProperties(array($field . '_name' => $tax_name_props)); $mapping->send(); } } } }
/** * Create new ES field mappings for the given fields from the configuration * TODO align callback names with Config::names so we can simply call this method with the kind string * @param array $config_fields * @param string $kind of internal fields: meta|field|taxonomy used to call the right indexer_map filter */ static function _map_values(&$properties, $type, $config_fields, $kind) { $index = self::_index(false); $numeric = Config::option('numeric'); $notanalyzed = Config::option('not_analyzed'); foreach ($config_fields as $field) { // set default $props = array('type' => 'string'); // detect special field type if (isset($numeric[$field])) { $props['type'] = 'float'; } elseif (isset($notanalyzed[$field]) || $kind == 'taxonomy' || $field == 'post_type') { $props['index'] = 'not_analyzed'; } elseif ($field == 'post_date') { $props['type'] = 'date'; $props['format'] = 'date_time_no_millis'; } else { $props['index'] = 'analyzed'; } if ($props['type'] == 'string' && $props['index'] == 'analyzed') { // provides more accurate searches $lang = Config::apply_filters('string_language', 'english'); $props = array('type' => 'multi_field', 'fields' => array($field => $props, $lang => array_merge($props, array('analyzer' => $lang)))); } // generic filter indexer_map_field| indexer_map_meta | indexer_map_taxonomy $props = Config::apply_filters('indexer_map_' . $kind, $props, $field); // also index taxonomy_name field if ($kind == 'taxonomy') { $tax_name_props = array('type' => 'string'); $tax_name_props = Config::apply_filters('indexer_map_taxonomy_name', $tax_name_props, $field); } $properties[$field] = $props; if (isset($tax_name_props)) { $properties[$field . '_name'] = $tax_name_props; } } }
<?php }); } }); add_action('init', function () { Theme::enableAjaxHooks(); $args = array(); $args['share_icons']['twitter'] = array('link' => 'http://twitter.com/parisholley', 'title' => 'Folow me on Twitter', 'img' => NHP_OPTIONS_URL . 'img/glyphicons/glyphicons_322_twitter.png'); $args['share_icons']['linked_in'] = array('link' => 'http://www.linkedin.com/in/parisholley', 'title' => 'Find me on LinkedIn', 'img' => NHP_OPTIONS_URL . 'img/glyphicons/glyphicons_337_linked_in.png'); $args['opt_name'] = 'elasticsearch'; $args['menu_title'] = 'ElasticSearch'; $args['page_title'] = 'ElasticSearch'; $args['page_slug'] = 'elastic_search'; $args['show_import_export'] = false; $args['page_position'] = 10241988; $args['dev_mode'] = false; $args['menu_icon'] = plugins_url('/wp/images/menu.png', __FILE__); $args['page_icon'] = 'elasticsearch-icon'; $sections = array(); require 'wp/admin/sections/wordpress-integration.php'; require 'wp/admin/sections/server-settings.php'; require 'wp/admin/sections/content-indexing.php'; require 'wp/admin/sections/field-mapping.php'; require 'wp/admin/sections/results-scoring.php'; require 'wp/admin/sections/manage-index.php'; global $NHP_Options; $tabs = array(); $sections = Config::apply_filters("nhp_options_section_setup", $sections); $args = Config::apply_filters("nhp_options_args_setup", $args); $NHP_Options = new \NHP_Options($sections, $args, $tabs); }, 10241988);
/** * @internal **/ public static function _buildQuery($search, $facets = array()) { global $blog_id; $search = str_ireplace(array(' and ', ' or '), array(' AND ', ' OR '), $search); $fields = array(); $musts = array(); $filters = array(); $scored = array(); foreach (Config::taxonomies() as $tax) { if ($search) { $score = Config::score('tax', $tax); if ($score > 0) { $scored[] = "{$tax}_name^{$score}"; } } self::_filterBySelectedFacets($tax, $facets, 'term', $musts, $filters); } $args = array(); $numeric = Config::option('numeric'); $exclude = Config::apply_filters('searcher_query_exclude_fields', array('post_date')); $fields = Config::fields(); self::_searchField($fields, 'field', $exclude, $search, $facets, $musts, $filters, $scored, $numeric); self::_searchField(Config::meta_fields(), 'meta', $exclude, $search, $facets, $musts, $filters, $scored, $numeric); if (count($scored) > 0 && $search) { $qs = array('fields' => $scored, 'query' => $search); $fuzzy = Config::option('fuzzy'); if ($fuzzy && strpos($search, "~") > -1) { $qs['fuzzy_min_sim'] = $fuzzy; } $qs = Config::apply_filters('searcher_query_string', $qs); $musts[] = array('query_string' => $qs); } if (in_array('post_type', $fields)) { self::_filterBySelectedFacets('post_type', $facets, 'term', $musts, $filters); } if (count($filters) > 0) { $args['filter']['bool']['should'] = $filters; } if (count($musts) > 0) { $args['query']['bool']['must'] = $musts; } $args['filter']['bool']['must'][] = array('term' => array('blog_id' => $blog_id)); $args = Config::apply_filters('searcher_query_pre_facet_filter', $args); if (in_array('post_type', $fields)) { $args['facets']['post_type']['terms'] = array('field' => 'post_type', 'size' => Config::apply_filters('searcher_query_facet_size', 100)); } // return facets foreach (Config::facets() as $facet) { $args['facets'][$facet]['terms'] = array('field' => $facet, 'size' => Config::apply_filters('searcher_query_facet_size', 100)); $args['facets'][$facet]['facet_filter'] = array('bool' => array('must' => array(array('term' => array('blog_id' => $blog_id))))); if (count($filters) > 0) { $applicable = array(); foreach ($filters as $filter) { if (isset($filter['term']) && !in_array($facet, array_keys($filter['term']))) { // do not filter on itself when using OR $applicable[] = $filter; } } if (count($applicable) > 0) { $args['facets'][$facet]['facet_filter']['bool']['should'] = $applicable; } } } if (is_array($numeric)) { foreach (array_keys($numeric) as $facet) { $ranges = Config::ranges($facet); if (count($ranges) > 0) { $args['facets'][$facet]['range'][$facet] = array_values($ranges); $args['facets'][$facet]['facet_filter'] = array('bool' => array('must' => array(array('term' => array('blog_id' => $blog_id))))); } } } return Config::apply_filters('searcher_query_post_facet_filter', $args); }
public static function _searchField($fields, $type, $exclude, $search, $facets, &$musts, &$filters, &$scored, $numeric) { foreach ($fields as $field) { if (in_array($field, $exclude)) { continue; } if ($search) { $score = Config::score($type, $field); $notanalyzed = Config::option('not_analyzed'); if ($score > 0) { if (strpos($search, "~") > -1 || isset($notanalyzed[$field])) { // TODO: fuzzy doesn't work with english analyzer $scored[] = "{$field}^{$score}"; } else { $scored[] = sprintf("{$field}.%s^{$score}", Config::apply_filters('string_language', 'english')); } } } if (isset($numeric[$field]) && $numeric[$field]) { $ranges = Config::ranges($field); if (count($ranges) > 0) { $transformed = array(); foreach ($ranges as $key => $range) { $transformed[$key] = array(); if (isset($range['to'])) { $transformed[$key]['lt'] = $range['to']; } if (isset($range['from'])) { $transformed[$key]['gte'] = $range['from']; } } self::_filterBySelectedFacets($field, $facets, 'range', $musts, $filters, $transformed); } } else { if ($type == 'custom') { self::_filterBySelectedFacets($field, $facets, 'term', $musts, $filters); } } } }
/** * Gather facet information for custom fields that were indexes. Example of output: * * <code> * array( * 'available' => array( * 'key1' => array( * 'count' => 4, * 'value' => 'value1' * ) * ), * 'selected' => array( * 'key2' => array( * 'count' => 6, * 'value' => 'value2' * ) * ), * 'total' => 10 * ) * </code> * * @param string $field Field to lookup in faceting data * * @return array An associative array based on example provided **/ static function custom($field) { global $wp_query; $data = isset($wp_query->facets[$field]) ? $wp_query->facets[$field] : array(); return self::_buildFacetResult($field, $data, function ($value) use($field, $data) { $return = array('slug' => $value); return Config::apply_filters('faceting_custom', $return, $field, $data); }); }