Mercurial > hg > solrsearch
diff plugins/facetapi/query_type_integer.inc @ 0:a2b4f67e73dc default tip
initial
author | Dirk Wintergruen <dwinter@mpiwg-berlin.mpg.de> |
---|---|
date | Mon, 08 Jun 2015 10:21:54 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/facetapi/query_type_integer.inc Mon Jun 08 10:21:54 2015 +0200 @@ -0,0 +1,223 @@ +<?php + +/** + * @file + * Date query type plugin for the Apache Solr adapter. + * @author dwinter + * + */ + + +/** + * Regex pattern for integer ranges. + */ +define('REGEX_INTEGER_RANGE', '/^\[(\d*) TO (\d*)\]$/'); + + +/** + * Plugin for "Integer" query types. + */ +class solrsearchFacetapiInteger extends FacetapiQueryType implements FacetapiQueryTypeInterface { + + /** + * Overrides FacetapiQueryType::extract(). + * + * Adds the "start" and "end" values for the integer range. + */ + public function extract(array $item) { + $return = array(); + if (preg_match(REGEX_INTEGER_RANGE, $item['value'], $matches)) { + + $return['start'] = $matches[1]; + $return['end'] = $matches[2]; + } + return $return; + } + + + /** + * Returns the query type associated with the plugin. + * + * @return string + * The query type. + */ + static public function getType() { + return 'integer'; + } + + /** + * Adds the filter to the query object. + * + * @param DrupalSolrQueryInterface $query + * An object containing the query in the backend's native API. + */ + public function execute($query) { + // Gets the data range in formats that Solr understands. + + $integer_range = $this->getIntegerRange($query); + + if (empty($integer_range)) { + return NULL; + } + list($start, $end, $gap) = $integer_range; + $query->addParam('facet.range', $this->facet['field']); + $query->addParam('f.' . $this->facet['field'] . '.facet.range.start', $start); + $query->addParam('f.' . $this->facet['field'] . '.facet.range.end', $end); + $query->addParam('f.' . $this->facet['field'] . '.facet.range.gap', $gap); + + // Adds "hard limit" parameter to prevent too many return values. + $settings = $this->adapter->getFacet($this->facet)->getSettings(); + $limit = empty($settings->settings['hard_limit']) ? 20 : (int) $settings->settings['hard_limit']; + $query->addParam('f.' . $this->facet['field'] . '.facet.limit', $limit); + + $active = $this->adapter->getActiveItems($this->facet); + // Date filters don't support OR operator. + foreach ($active as $value => $item) { + $query->addFilter($this->facet['field'], $value); + } + } + + /** + * Gets the range of integer rage we are using. + * + * @param DrupalSolrQueryInterface $query + * A SolrBaseQuery object. + * + * @return bool|array + * An array containing the gap and range information or false if not present + */ + function getIntegerRange(DrupalSolrQueryInterface $query) { + + $return = NULL; + $gap = NULL; + + // Attempts to get next gap from passed date filters. + foreach ($this->adapter->getActiveItems($this->facet) as $item) { + + if ($gap = ($item['end'] - $item['start'])) { + //$next_gap = facetapi_get_next_date_gap($gap, FACETAPI_DATE_SECOND); + //TODO: is something similar needed for integer range? + $next_gap =$gap; + if ($next_gap == $gap) { + $next_gap = NULL; + return NULL; + } + $return = array( + $item['start'], + $item['end'], + $next_gap, + ); + } + } + + // If no filters were passed, get default range. + if (NULL === $return) { + + // Builds SQL that gets minimum and maximum values from node table. + $minimum = $maximum =$gap = FALSE; + if ($this->facet['min callback'] && is_callable($this->facet['min callback'])) { + $minimum = $this->facet['min callback']($this->facet); + } + if ($this->facet['max callback'] && is_callable($this->facet['max callback'])) { + $maximum = $this->facet['max callback']($this->facet); + } + + if ($this->facet['gap callback'] && is_callable($this->facet['gap callback'])) { + $gap = $this->facet['gap callback']($this->facet); + } + + + // Gets the default gap. + //$gap = FACETAPI_DATE_YEAR; + if ($minimum && $maximum && $gap) { + + //$minimum = facetapi_isodate($minimum, $gap); + //$maximum = facetapi_isodate($maximum, $gap); + $return = array( + $minimum, + $maximum, + $gap , + ); + } + } + // Returns the range information. + return $return; + } + + /** + * Initializes the facet's build array. + * + * @return array + * The initialized render array. + */ + public function build() { + + // Initializes build and gets static response. + if (!$response = solrsearch_static_response_cache($this->adapter->getSearcher())) { + return array(); + } + $build = array(); + + // Gets total number of documents matched in search. + $total = $response->response->numFound; + + // Gets the active date facets, starts to builds the "parent - child" + // relationships. + $parent = NULL; + foreach ($this->adapter->getActiveItems($this->facet) as $value => $item) { + // Builds the raw facet "value", the count for selected items will be the + // total number of rows returned in the query. + $build[$value] = array('#count' => $total); + + // If there is a previous item, there is a parent, uses a reference so the + // arrays are populated when they are updated. + if (NULL !== $parent) { + $build[$parent]['#item_children'][$value] = &$build[$value]; + $build[$value]['#item_parents'][$parent] = $parent; + } + + // Stores the last value iterated over. + $parent = $value; + } + + // Gets raw facet data from the Solr server. + if (isset($response->facet_counts->facet_ranges) && isset($response->facet_counts->facet_ranges->{$this->facet['field']})) { + $raw_data = (array) $response->facet_counts->facet_ranges->{$this->facet['field']}; + } + else { + $raw_data = array(); + } + //$end = (!empty($raw_data['end'])) ? $raw_data['end'] : ''; + //$start = (!empty($raw_data['start'])) ? $raw_data['start'] : ''; + $gap = (!empty($raw_data['gap'])) ? $raw_data['gap'] : ''; + + // We cannot list anything below a minute (range of 00 seconds till 59 + // seconds. Milliseconds are not possible) + + unset($raw_data['start']); + unset($raw_data['end']); + unset($raw_data['gap']); + + // Treat each date facet as a range start, and use the next date facet + // as range end. Use 'end' for the final end. + $previous = NULL; + + // Builds facet counts object used by the server. + + foreach ($raw_data as $value => $counts) { + foreach($counts as $val => $count){ + if ($count) { + $from = $val; + $to = $val+$gap; + $new_value = '[' . $from . ' TO ' . $to . ']'; + $build[$new_value] = array('#count' => $count, '#active' => 0); + if (NULL !== $parent) { + $build[$parent]['#item_children'][$new_value] = &$build[$new_value]; + $build[$new_value]['#item_parents'][$parent] = $parent; + } + } + } + } + return $build; + } +}