Overview

Namespaces

  • elasticsearch

Classes

  • Config
  • Defaults
  • Faceting
  • Indexer
  • Searcher
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: namespace elasticsearch;
  3: 
  4: /**
  5: * The searcher class provides all you need to query your ElasticSearch server.
  6: *
  7: * @license http://opensource.org/licenses/MIT
  8: * @author Paris Holley <[email protected]>
  9: * @version 2.0.0
 10: **/
 11: class Searcher{
 12:     /**
 13:     * Initiate a search with the ElasticSearch server and return the results. Use Faceting to manipulate URLs.
 14:     * @param string $search A space delimited list of terms to search for
 15:     * @param integer $pageIndex The index that represents the current page
 16:     * @param integer $size The number of results to return per page
 17:     * @param array $facets An object that contains selected facets (typically the query string, ie: $_GET)
 18:     * @param boolean $sortByDate If false, results will be sorted by score (relevancy)
 19:     * @see Faceting
 20:     * 
 21:     * @return array The results of the search
 22:     **/
 23:     public static function search($search, $pageIndex = 0, $size = 10, $facets = array(), $sortByDate = false){
 24:         $args = self::_buildQuery($search, $facets);
 25: 
 26:         if(empty($args) || (empty($args['query']) && empty($args['facets']))){
 27:             return array(
 28:                 'total' => 0,
 29:                 'ids' => array(),
 30:                 'facets' => array()
 31:             );
 32:         }
 33: 
 34:         return self::_query($args, $pageIndex, $size, $sortByDate);
 35:     }
 36: 
 37:     /**
 38:     * @internal
 39:     **/
 40:     public static function _query($args, $pageIndex, $size, $sortByDate = false){
 41:         $query =new \Elastica\Query($args);
 42:         $query->setFrom($pageIndex * $size);
 43:         $query->setSize($size);
 44:         $query->setFields(array('id'));
 45: 
 46:         Config::apply_filters('searcher_query', $query);
 47: 
 48:         try{
 49:             $index = Indexer::_index(false);
 50: 
 51:             $search = new \Elastica\Search($index->getClient());
 52:             $search->addIndex($index);
 53:             
 54:             if($sortByDate){
 55:                 $query->addSort(array('post_date' => 'desc'));
 56:             }else{
 57:                 $query->addSort('_score');
 58:             }
 59: 
 60:             Config::apply_filters('searcher_search', $search);
 61: 
 62:             $results = $search->search($query);
 63: 
 64:             return self::_parseResults($results);
 65:         }catch(\Exception $ex){
 66:             error_log($ex);
 67: 
 68:             return null;
 69:         }
 70:     }
 71: 
 72:     /**
 73:     * @internal
 74:     **/
 75:     public static function _parseResults($response){
 76:         $val = array(
 77:             'total' => $response->getTotalHits(),
 78:             'facets' => array(),
 79:             'ids' => array()
 80:         );
 81: 
 82:         foreach($response->getFacets() as $name => $facet){
 83:             if(isset($facet['terms'])){
 84:                 foreach($facet['terms'] as $term){
 85:                     $val['facets'][$name][$term['term']] = $term['count'];
 86:                 }
 87:             }
 88: 
 89:             if(isset($facet['ranges'])){
 90:                 foreach($facet['ranges'] as $range){
 91:                     $from = isset($range['from']) ? $range['from'] : '';
 92:                     $to = isset($range['to']) ? $range['to'] : '';
 93: 
 94:                     $val['facets'][$name][$from . '-' . $to] = $range['count'];
 95:                 }
 96:             }
 97:         }
 98: 
 99:         foreach($response->getResults() as $result){
100:             $val['ids'][] = $result->getId();
101:         }
102: 
103:         return Config::apply_filters('searcher_results', $val, $response);      
104:     }
105: 
106:     /**
107:     * @internal
108:     **/
109:     public static function _buildQuery($search, $facets = array()){
110:         global $blog_id;
111: 
112:         $search = str_ireplace(array(' and ', ' or '), array(' AND ', ' OR '), $search);
113: 
114:         $fields = array();
115:         $musts = array();
116:         $filters = array();
117: 
118:         foreach(Config::taxonomies() as $tax){
119:             if($search){
120:                 $score = Config::score('tax', $tax);
121: 
122:                 if($score > 0){
123:                     $fields[] = "{$tax}_name^$score";
124:                 }
125:             }
126: 
127:             self::_filterBySelectedFacets($tax, $facets, 'term', $musts, $filters);
128:         }
129: 
130:         $args = array();
131: 
132:         $numeric = Config::option('numeric');
133: 
134:         $exclude = Config::apply_filters('searcher_query_exclude_fields', array('post_date'));
135: 
136:         foreach(Config::fields() as $field){
137:             if(in_array($field, $exclude)){
138:                 continue;
139:             }
140: 
141:             if($search){
142:                 $score = Config::score('field', $field);
143: 
144:                 if($score > 0){
145:                     $fields[] = "$field^$score";
146:                 }
147:             }
148: 
149:             if(isset($numeric[$field]) && $numeric[$field]){
150:                 $ranges = Config::ranges($field);
151: 
152:                 if(count($ranges) > 0 ){
153:                     self::_filterBySelectedFacets($field, $facets, 'range', $musts, $filters, $ranges);
154:                 }
155:             }
156:         }
157: 
158:         if(count($fields) > 0){
159:             $qs = array(
160:                 'fields' => $fields,
161:                 'query' => $search
162:             );
163: 
164:             $fuzzy = Config::option('fuzzy');
165: 
166:             if($fuzzy && strpos($search, "~") > -1){
167:                 $qs['fuzzy_min_sim'] = $fuzzy;
168:             }
169: 
170:             $qs = Config::apply_filters('searcher_query_string', $qs);
171: 
172:             $args['query']['query_string'] = $qs;
173:         }
174: 
175:         if(count($filters) > 0){
176:             $args['filter']['bool']['should'] = $filters;
177:         }
178: 
179:         if(count($musts) > 0){
180:             $args['query']['bool']['must'] = $musts;
181:         }
182: 
183:         $args['filter']['bool']['must'][] = array( 'term' => array( 'blog_id' => $blog_id ) );
184: 
185:         $args = Config::apply_filters('searcher_query_pre_facet_filter', $args);
186: 
187:         // return facets
188:         foreach(Config::facets() as $facet){
189:             $args['facets'][$facet]['terms']['field'] = $facet;
190:             $args['facets'][$facet]['facet_filter'] = array( 'term' => array( 'blog_id' => $blog_id ) );
191:         }
192: 
193:         if(is_array($numeric)){
194:             foreach(array_keys($numeric) as $facet){
195:                 $ranges = Config::ranges($facet);
196: 
197:                 if(count($ranges) > 0 ){
198:                     $args['facets'][$facet]['range'][$facet] = array_values($ranges);
199:                     $args['facets'][$facet]['facet_filter'] = array( 'term' => array( 'blog_id' => $blog_id ) );
200:                 }
201:             }
202:         }
203:         
204:         return Config::apply_filters('searcher_query_post_facet_filter', $args);
205:     }
206: 
207:     /**
208:     * @internal
209:     **/
210:     public static function _filterBySelectedFacets($name, $facets, $type, &$musts, &$filters, $translate = array()){
211:         if(isset($facets[$name])){
212:             $output = &$musts;
213: 
214:             $facets = $facets[$name];
215: 
216:             if(!is_array($facets)){
217:                 $facets = array($facets);
218:             }
219: 
220:             foreach($facets as $operation => $facet){
221:                 if(is_string($operation) && $operation == 'or'){
222:                     // use filters so faceting isn't affecting, allowing the user to select more "or" options
223:                     $output = &$filters;
224:                 }
225: 
226:                 if(is_array($facet)){
227:                     foreach($facet as $value){
228:                         $output[] = array( $type => array( $name => isset($translate[$value]) ? $translate[$value] : $value ));
229:                     }
230: 
231:                     continue;
232:                 }
233:                 
234:                 $output[] = array( $type => array( $name => isset($translate[$facet]) ? $translate[$facet] : $facet ));
235:             }
236:         }
237:     }
238: }
239: ?>
240: 
API documentation generated by ApiGen 2.8.0