%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /www/varak.net/wiki.varak.net/extensions/CirrusSearch/includes/Search/
Upload File :
Create Path :
Current File : /www/varak.net/wiki.varak.net/extensions/CirrusSearch/includes/Search/SearchContext.php

<?php

namespace CirrusSearch\Search;

use CirrusSearch\SearchConfig;
use GeoData\Coord;
use Elastica\Query\AbstractQuery;

/**
 * The search context, maintains the state of the current search query.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 * http://www.gnu.org/copyleft/gpl.html
 */

/**
 * The SearchContext stores the various states maintained
 * during the query building process.
 */
class SearchContext {
	/**
	 * @var SearchConfig
	 */
	private $config;

	/**
	 * @var int[]|null list of namespaces
	 */
	private $namespaces;

	/**
	 * @var array|null list of boost templates extracted from the query string
	 */
	private $boostTemplatesFromQuery;

	/**
	 * @deprecated use rescore profiles instead
	 * @var bool do we need to boost links
	 */
	private $boostLinks = false;

	/**
	 * @var float portion of article's score which decays with time.  Defaults to 0 meaning don't decay the score
	 *  with time since the last update.
	 */
	private $preferRecentDecayPortion = 0;

	/**
	 * @var float number of days it takes an the portion of an article score that will decay with time
	 *  since last update to decay half way.  Defaults to 0 meaning don't decay the score with time.
	 */
	private $preferRecentHalfLife = 0;

	/**
	 * @var string rescore profile to use
	 */
	private $rescoreProfile;

	/**
	 * @var array[] nested array of arrays. Each child array contains three keys:
	 * coord, radius and weight. Used for geographic radius boosting.
	 */
	private $geoBoosts = [];

	/**
	 * @var bool Could this query possibly return results?
	 */
	private $resultsPossible = true;

	/**
	 * @var string[] List of features in the user suplied query string. Features are
	 *  held in the array key, value is always true.
	 */
	private $syntaxUsed = [];

	/**
	 * @var string The type of search being performed. ex: full_text, near_match, prefix, etc.
	 */
	private $searchType = 'unknown';

	/**
	 * @var AbstractQuery[] List of filters that query results must match
	 */
	private $filters = [];

	/**
	 * @var AbstractQuery[] List of filters that query results must not match
	 */
	private $notFilters = [];

	/**
	 * @var array[] $config List of configurations for highlighting the article
	 *  source. Passed to ResultType::getHighlightingConfiguration to generate
	 *  final highlighting configuration. Empty if source is ignored.
	 */
	private $highlightSource = [];

	/**
	 * @var boolean is this a fuzzy query?
	 */
	private $fuzzyQuery = false;

	/**
	 * @var AbstractQuery|null Query that should be used for highlighting if different
	 *  from the query used for selecting.
	 */
	private $highlightQuery;

	/**
	 * @var AbstractQuery[] queries that don't use Elastic's "query string" query,
	 *  for more advanced highlighting (e.g. match_phrase_prefix for regular
	 *  quoted strings).
	 */
	private $nonTextHighlightQueries = [];

	/**
	 * @var array Set of rescore configurations as used by elasticsearch. The query needs
	 *  to be an Elastica query.
	 */
	private $rescore = [];

	/**
	 * @var string[] array of prefixes that should be prepended to suggestions. Can be added
	 *  to externally and is added to during search syntax parsing.
	 */
	private $suggestPrefixes = [];

	/**
	 * @var string[] array of suffixes that should be prepended to suggestions. Can be added
	 *  to externally and is added to during search syntax parsing.
	 */
	private $suggestSuffixes = [];

	/**
	 * @var AbstractQuery|null main query. null defaults to MatchAll
	 */
	private $mainQuery;

	/**
	 * @var \Elastica\Query\Match[] Queries that don't use Elastic's "query string" query, for
	 *  more advanced searching (e.g. match_phrase_prefix for regular quoted strings).
	 */
	private $nonTextQueries = [];

	/**
	 * @var array|null Configuration for suggest query
	 */
	private $suggest;

	/**
	 * @var bool Should this search limit results to the local wiki?
	 */
	private $limitSearchToLocalWiki = false;

	/**
	 * @param SearchConfig $config
	 * @param int[]|null $namespaces
	 */
	public function __construct( SearchConfig $config, array $namespaces = null ) {
		$this->config = $config;
		$this->boostLinks = $this->config->get( 'CirrusSearchBoostLinks' );
		$this->namespaces = $namespaces;
		$this->rescoreProfile = $this->config->get( 'CirrusSearchRescoreProfile' );

		$decay = $this->config->get( 'CirrusSearchPreferRecentDefaultDecayPortion' );
		if ( $decay > 0 ) {
			$this->preferRecentDecayPortion = $decay;
			$this->preferRecentHalfLife = $this->config->get( 'CirrusSearchPreferRecentDefaultHalfLife' );
		}
	}

	/**
	 * @return SearchConfig the Cirrus config object
	 */
	public function getConfig() {
		return $this->config;
	}

	/**
	 * mediawiki namespace id's being requested.
	 * NOTE: this value may change during the Searcher process.
	 *
	 * @return int[]|null
	 */
	public function getNamespaces() {
		return $this->namespaces;
	}

	/**
	 * set the mediawiki namespace id's
	 *
	 * @param int[]|null $namespaces array of integer
	 */
	public function setNamespaces( $namespaces ) {
		$this->namespaces = $namespaces;
	}

	/**
	 * Return the list of boosted templates specified in the user query (special syntax)
	 * null if not used in the query or an empty array if there was a syntax error.
	 * Initialized after special syntax extraction.
	 *
	 * @return array|null of boosted templates, key is the template value is the weight
	 */
	public function getBoostTemplatesFromQuery() {
		return $this->boostTemplatesFromQuery;
	}

	/**
	 * @param array $boostTemplatesFromQuery boosted templates extracted from query
	 */
	public function setBoostTemplatesFromQuery( $boostTemplatesFromQuery ) {
		$this->boostTemplatesFromQuery = $boostTemplatesFromQuery;
	}

	/**
	 * @deprecated use rescore profiles
	 * @param bool $boostLinks Deactivate IncomingLinksFunctionScoreBuilder if present in the rescore profile
	 */
	public function setBoostLinks( $boostLinks ) {
		$this->boostLinks = $boostLinks;
	}

	/**
	 * @deprecated use custom rescore profile
	 * @return bool
	 * @suppress PhanDeprecatedProperty
	 */
	public function isBoostLinks() {
		return $this->boostLinks;
	}

	/**
	 * Set prefer recent options
	 *
	 * @param float $preferRecentDecayPortion
	 * @param float $preferRecentHalfLife
	 */
	public function setPreferRecentOptions( $preferRecentDecayPortion, $preferRecentHalfLife ) {
		$this->preferRecentDecayPortion = $preferRecentDecayPortion;
		$this->preferRecentHalfLife = $preferRecentHalfLife;
	}


	/**
	 * @return bool true if preferRecent options have been set.
	 */
	public function hasPreferRecentOptions() {
		return $this->preferRecentHalfLife > 0 && $this->preferRecentDecayPortion > 0;
	}

	/**
	 * Parameter used by Search\PreferRecentFunctionScoreBuilder
	 *
	 * @return float the decay portion for prefer recent
	 */
	public function getPreferRecentDecayPortion() {
		return $this->preferRecentDecayPortion;
	}

	/**
	 * Parameter used by Search\PreferRecentFunctionScoreBuilder
	 *
	 * @return float the half life for prefer recent
	 */
	public function getPreferRecentHalfLife() {
		return $this->preferRecentHalfLife;
	}

	/**
	 * @return string the rescore profile to use
	 */
	public function getRescoreProfile() {
		return $this->rescoreProfile;
	}

	/**
	 * @param string the rescore profile to use
	 */
	public function setRescoreProfile( $rescoreProfile ) {
		$this->rescoreProfile = $rescoreProfile;
	}

	/**
	 * @return array[] nested array of arrays. Each child array contains three keys:
	 * coord, radius and weight
	 */
	public function getGeoBoosts() {
		return $this->geoBoosts;
	}

	/**
	 * @param Coord $coord Coordinates to boost near
	 * @param int $radius radius to boost within, in meters
	 * @param float $weight Number to multiply score by when within radius
	 */
	public function addGeoBoost( Coord $coord, $radius, $weight ) {
		$this->geoBoosts[] = [
			'coord' => $coord,
			'radius' => $radius,
			'weight' => $weight,
		];
	}

	/**
	 * @return bool Could this query possibly return results?
	 */
	public function areResultsPossible() {
		return $this->resultsPossible;
	}

	/**
	 * @param bool $possible Could this query possible return results? Defaults to true
	 *  if not called.
	 */
	public function setResultsPossible( $possible ) {
		$this->resultsPossible = $possible;
	}

	/**
	 * @var string|null $type type of syntax to check, null for any type
	 * @return bool True when the query uses $type kind of special syntax
	 */
	public function isSyntaxUsed( $type = null ) {
		if ( $type === null ) {
			return count( $this->syntaxUsed ) > 0;
		}
		return isset( $this->syntaxUsed[$type] );
	}

	/**
	 * @return string[] List of special syntax used in the query
	 */
	public function getSyntaxUsed() {
		return array_keys( $this->syntaxUsed );
	}

	/**
	 * @param string $feature Name of a syntax feature used in the query string
	 */
	public function addSyntaxUsed( $feature ) {
		$this->syntaxUsed[$feature] = true;
	}

	/**
	 * @return string The type of search being performed, ex: full_text, near_match, prefix, etc.
	 * @todo It might be possible to determine this based on the features used.
	 */
	public function getSearchType() {
		return $this->searchType;
	}

	/**
	 * @param string $type The type of search being performed. ex: full_text, near_match, prefix, etc.
	 */
	public function setSearchType( $type ) {
		$this->searchType = $type;
	}

	/**
	 * @param AbstractQuery $filter Query results must match this filter
	 */
	public function addFilter( AbstractQuery $filter ) {
		$this->filters[] = $filter;
	}

	/**
	 * @param AbstractQuery $filter Query results must not match this filter
	 */
	public function addNotFilter( AbstractQuery $filter ) {
		$this->notFilters[] = $filter;
	}

	/**
	 * @param bool $isFuzzy is this a fuzzy query?
	 */
	public function setFuzzyQuery( $isFuzzy ) {
		$this->fuzzyQuery = $isFuzzy;
	}

	/**
	 * @return bool is this a fuzzy query?
	 */
	public function isFuzzyQuery() {
		return $this->fuzzyQuery;
	}

	/**
	 * @param array $config Configuration for highlighting the article source. Passed
	 *  to ResultType::getHighlightingConfiguration to generate final highlighting
	 *  configuration.
	 */
	public function addHighlightSource( array $config ) {
		$this->highlightSource[] = $config;
	}

	/**
	 * @param AbstractQuery Query that should be used for highlighting if different
	 *  from the query used for selecting.
	 */
	public function setHighlightQuery( AbstractQuery $query ) {
		$this->highlightQuery = $query;
	}

	/**
	 * @param AbstractQuery $query queries that don't use Elastic's "query
	 * string" query, for more advanced highlighting (e.g. match_phrase_prefix
	 * for regular quoted strings).
	 */
	public function addNonTextHighlightQuery( AbstractQuery $query ) {
		$this->nonTextHighlightQueries[] = $query;
	}

	/**
	 * @return array|null Highlight portion of query to be sent to elasticsearch
	 */
	public function getHighlight( ResultsType $resultsType ) {
		$highlight = $resultsType->getHighlightingConfiguration( $this->highlightSource );
		if ( !$highlight ) {
			return null;
		}
		if ( $this->fuzzyQuery ) {
			$highlight['fields'] = array_filter(
				$highlight['fields'],
				function ( $field ) {
					return $field['type'] !== 'plain';
				}
			);
		}
		$query = $this->getHighlightQuery();
		if ( $query ) {
			$highlight['highlight_query'] = $query->toArray();
		}

		return $highlight;
	}

	/**
	 * @return AbstractQuery|null Query that should be used for highlighting if different
	 *  from the query used for selecting.
	 */
	private function getHighlightQuery() {
		if ( empty( $this->nonTextHighlightQueries ) ) {
			return $this->highlightQuery;
		}

		$bool = new \Elastica\Query\BoolQuery();
		if ( $this->highlightQuery) {
			$bool->addShould( $this->highlightQuery );
		}
		foreach ( $this->nonTextHighlightQueries as $nonTextHighlightQuery ) {
			$bool->addShould( $nonTextHighlightQuery );
		}

		return $bool;
	}

	/**
	 * @return bool True if rescore queries are attached
	 */
	public function hasRescore() {
		return count( $this->rescore ) > 0;
	}

	/**
	 * rescore_query has to be in array form before we send it to Elasticsearch but it is way
	 * easier to work with if we leave it in query form until now
	 *
	 * @return array[] Rescore configurations as used by elasticsearch.
	 */
	public function getRescore() {
		$result = [];
		foreach ( $this->rescore as $rescore ) {
			$rescore['query']['rescore_query'] = $rescore['query']['rescore_query']->toArray();
			$result[] = $rescore;
		}

		return $result;
	}

	/**
	 * @param array[] $rescore Rescore configuration as used by elasticsearch. The query needs
	 *  to be an Elastica query.
	 */
	public function addRescore( array $rescore ) {
		$this->rescore[] = $rescore;
	}

	/**
	 * Remove all rescores from the query. Used when it is known that extra work scoring
	 * results will not be useful or necessary. Only effective if done *after* all rescores
	 * have been added.
	 */
	public function clearRescore() {
		$this->rescore = [];
	}

	/**
	 * @param array[] $rescores A set of rescore configurations as used by elasticsearch. The
	 *  query needs to be an Elastica query.
	 */
	public function mergeRescore( $rescores ) {
		$this->rescore = array_merge( $this->rescore, $rescores );
	}

	/**
	 * @return string[] List of prefixes to be prepended to suggestions
	 */
	public function getSuggestPrefixes() {
		return $this->suggestPrefixes;
	}

	/**
	 * @param string $prefix Prefix to be prepended to suggestions
	 */
	public function addSuggestPrefix( $prefix ) {
		$this->suggestPrefixes[] = $prefix;
	}

	/**
	 * @return string[] List of suffixes to be appended to suggestions
	 */
	public function getSuggestSuffixes() {
		return $this->suggestSuffixes;
	}

	/**
	 * @param string $suffix Suffix to be appended to suggestions
	 */
	public function addSuggestSuffix( $suffix ) {
		$this->suggestSuffixes[] = $suffix;
	}

	/**
	 * @return AbstractQuery The primary query to be sent to elasticsearch. Includes
	 *  the main query, non text queries, and any additional filters.
	 */
	public function getQuery() {
		if ( empty( $this->nonTextQueries ) ) {
			$mainQuery = $this->mainQuery ?: new \Elastica\Query\MatchAll();
		} else {
			$mainQuery = new \Elastica\Query\BoolQuery();
			if ( $this->mainQuery ) {
				$mainQuery ->addMust( $this->mainQuery );
			}
			foreach ( $this->nonTextQueries as $nonTextQuery ) {
				$mainQuery->addMust( $nonTextQuery );
			}
		}
		// Wrap $mainQuery in a filtered query if there are any filters
		$unifiedFilter = Filters::unify( $this->filters, $this->notFilters );
		if ( $unifiedFilter !== null ) {
			if ( ! ( $mainQuery instanceof \Elastica\Query\BoolQuery ) ) {
				$bool = new \Elastica\Query\BoolQuery();
				$bool->addMust( $mainQuery );
				$mainQuery = $bool;
			}
			$mainQuery->addFilter( $unifiedFilter );
		}


		return $mainQuery;
	}

	/**
	 * @param AbstractQuery $query The primary query to be passed to
	 *  elasticsearch.
	 */
	public function setMainQuery( AbstractQuery $query ) {
		$this->mainQuery = $query;
	}

	/**
	 * @param \Elastica\Query\Match $match Queries that don't use Elastic's
	 * "query string" query, for more advanced searching (e.g.
	 *  match_phrase_prefix for regular quoted strings).
	 */
	public function addNonTextQuery( \Elastica\Query\Match $match ) {
		$this->nonTextQueries[] = $match;
	}

	/**
	 * @return array|null Configuration for suggest query
	 */
	public function getSuggest() {
		return $this->suggest;
	}

	/**
	 * @param array $suggest Configuration for suggest query
	 */
	public function setSuggest( array $suggest ) {
		$this->suggest = $suggest;
	}

	/**
	 * @return boolean Should this search limit results to the local wiki? If
	 *  not called the default is false.
	 */
	public function getLimitSearchToLocalWiki() {
		return $this->limitSearchToLocalWiki;
	}

	/**
	 * @param boolean $localWikiOnly Should this search limit results to the local wiki? If
	 *  not called the default is false.
	 */
	public function setLimitSearchToLocalWiki( $localWikiOnly ) {
		$this->limitSearchToLocalWiki = $localWikiOnly;
	}
}

Zerion Mini Shell 1.0