UNPKG

elastic-builder

Version:

A JavaScript implementation of the elasticsearch Query DSL

448 lines (386 loc) 17.3 kB
'use strict'; var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var isNil = require('lodash.isnil'); var _require = require('../../core'), _require$util = _require.util, checkType = _require$util.checkType, invalidParam = _require$util.invalidParam, MULTI_MATCH_TYPE = _require.consts.MULTI_MATCH_TYPE; var FullTextQueryBase = require('./full-text-query-base'); var _require2 = require('../helper'), validateRewiteMethod = _require2.validateRewiteMethod; var ES_REF_URL = 'https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html'; var invalidTypeParam = invalidParam(ES_REF_URL, 'type', MULTI_MATCH_TYPE); var invalidOperatorParam = invalidParam(ES_REF_URL, 'operator', "'and' or 'or'"); var invalidBehaviorParam = invalidParam(ES_REF_URL, 'behavior', "'all' or 'none'"); /** * A `MultiMatchQuery` query builds further on top of the * `MultiMatchQuery` by allowing multiple fields to be specified. * The idea here is to allow to more easily build a concise match type query * over multiple fields instead of using a relatively more expressive query * by using multiple match queries within a bool query. * * [Elasticsearch reference](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html) * * @example * const qry = esb.multiMatchQuery(['subject', 'message'], 'this is a test'); * * @param {Array<string>|string=} fields The fields to be queried * @param {string=} queryString The query string * * @extends FullTextQueryBase */ var MultiMatchQuery = function (_FullTextQueryBase) { (0, _inherits3.default)(MultiMatchQuery, _FullTextQueryBase); // Extremely similar to match query. // mixins are one way to go about it. // repeating code for now // eslint-disable-next-line require-jsdoc function MultiMatchQuery(fields, queryString) { (0, _classCallCheck3.default)(this, MultiMatchQuery); // This field is required // Avoid checking for key in `this.field` var _this = (0, _possibleConstructorReturn3.default)(this, (MultiMatchQuery.__proto__ || Object.getPrototypeOf(MultiMatchQuery)).call(this, 'multi_match', queryString)); _this._queryOpts.fields = []; if (!isNil(fields)) { if (Array.isArray(fields)) _this.fields(fields);else _this.field(fields); } return _this; } /** * Appends given field to the list of fields to search against. * Fields can be specified with wildcards. * Individual fields can be boosted with the caret (^) notation. * Example - `"subject^3"` * * @param {string} field One of the fields to be queried * @returns {MultiMatchQuery} returns `this` so that calls can be chained. */ (0, _createClass3.default)(MultiMatchQuery, [{ key: 'field', value: function field(_field) { this._queryOpts.fields.push(_field); return this; } /** * Appends given fields to the list of fields to search against. * Fields can be specified with wildcards. * Individual fields can be boosted with the caret (^) notation. * * @example * // Boost individual fields with caret `^` notation * const qry = esb.multiMatchQuery(['subject^3', 'message'], 'this is a test'); * * @example * // Specify fields with wildcards * const qry = esb.multiMatchQuery(['title', '*_name'], 'Will Smith'); * * @param {Array<string>} fields The fields to be queried * @returns {MultiMatchQuery} returns `this` so that calls can be chained. */ }, { key: 'fields', value: function fields(_fields) { checkType(_fields, Array); this._queryOpts.fields = this._queryOpts.fields.concat(_fields); return this; } /** * Sets the type of multi match query. Valid values are: * - `best_fields` - (default) Finds documents which match any field, * but uses the `_score` from the best field. * * - `most_fields` - Finds documents which match any field and combines * the `_score` from each field. * * - `cross_fields` - Treats fields with the same `analyzer` as though * they were one big field. Looks for each word in *any* field * * - `phrase` - Runs a `match_phrase` query on each field and combines * the `_score` from each field. * * - `phrase_prefix` - Runs a `match_phrase_prefix` query on each field * and combines the `_score` from each field. * * - `bool_prefix` - (added in v7.2) Creates a match_bool_prefix query on each field and * combines the _score from each field. * * @example * // Find the single best matching field * const qry = esb.multiMatchQuery(['subject', 'message'], 'brown fox') * .type('best_fields') * .tieBreaker(0.3); * * @example * // Query multiple fields analyzed differently for the same text * const qry = esb.multiMatchQuery( * ['title', 'title.original', 'title.shingles'], * 'quick brown fox' * ).type('most_fields'); * * @example * // Run a `match_phrase_prefix` query on multiple fields * const qry = esb.multiMatchQuery( * ['subject', 'message'], * 'quick brown f' * ).type('phrase_prefix'); * * @example * // All terms must be present in at least one field for document to match * const qry = esb.multiMatchQuery(['first_name', 'last_name'], 'Will Smith') * .type('cross_fields') * .operator('and'); * * @param {string} type Can be one of `best_fields`, `most_fields`, * `cross_fields`, `phrase`, `phrase_prefix` and `bool_prefix`. Default is * `best_fields`. * @returns {MultiMatchQuery} returns `this` so that calls can be chained. */ }, { key: 'type', value: function type(_type) { if (isNil(_type)) invalidTypeParam(_type); var typeLower = _type.toLowerCase(); if (!MULTI_MATCH_TYPE.has(typeLower)) invalidTypeParam(_type); this._queryOpts.type = typeLower; return this; } /** * The tie breaker value. The tie breaker capability allows results * that include the same term in multiple fields to be judged better than * results that include this term in only the best of those multiple * fields, without confusing this with the better case of two different * terms in the multiple fields. Default: `0.0`. * * @param {number} factor * @returns {MultiMatchQuery} returns `this` so that calls can be chained. */ }, { key: 'tieBreaker', value: function tieBreaker(factor) { this._queryOpts.tie_breaker = factor; return this; } /** * The operator to be used in the boolean query which is constructed * by analyzing the text provided. The `operator` flag can be set to `or` or * `and` to control the boolean clauses (defaults to `or`). * * @param {string} operator Can be `and`/`or`. Default is `or`. * @returns {MultiMatchQuery} returns `this` so that calls can be chained. */ }, { key: 'operator', value: function operator(_operator) { if (isNil(_operator)) invalidOperatorParam(_operator); var operatorLower = _operator.toLowerCase(); if (operatorLower !== 'and' && operatorLower !== 'or') { invalidOperatorParam(_operator); } this._queryOpts.operator = operatorLower; return this; } /** * Sets the `lenient` parameter which allows to ignore exceptions caused * by data-type mismatches such as trying to query a numeric field with a * text query string when set to `true`. * * @param {boolean} enable Defaules to `false` * @returns {MultiMatchQuery} returns `this` so that calls can be chained. */ }, { key: 'lenient', value: function lenient(enable) { this._queryOpts.lenient = enable; return this; } // phrase_slop is a synonym for slop. // haven't added method for it.. /** * Configures the `slop`(default is 0) for matching terms in any order. * Transposed terms have a slop of 2. * * @param {number} slop A positive integer value, defaults is 0. * @returns {MultiMatchQuery} returns `this` so that calls can be chained. */ }, { key: 'slop', value: function slop(_slop) { this._queryOpts.slop = _slop; return this; } /** * Sets the `fuzziness` parameter which is interpreted as a Levenshtein Edit Distance — * the number of one character changes that need to be made to one string to make it * the same as another string. * * The `fuzziness` parameter cannot be used with the `phrase`, `phrase_prefix` * or `cross_fields` type. * * @param {number|string} factor Can be specified either as a number, or the maximum * number of edits, or as `AUTO` which generates an edit distance based on the length * of the term. * @returns {MultiMatchQuery} returns `this` so that calls can be chained. */ }, { key: 'fuzziness', value: function fuzziness(factor) { this._queryOpts.fuzziness = factor; return this; } /** * Sets the prefix length for a fuzzy prefix `MultiMatchQuery` * * @param {number} len * @returns {MultiMatchQuery} returns `this` so that calls can be chained. */ }, { key: 'prefixLength', value: function prefixLength(len) { this._queryOpts.prefix_length = len; return this; } /** * Sets the max expansions for a fuzzy prefix `MultiMatchQuery` * * @param {number} limit * @returns {MultiMatchQuery} returns `this` so that calls can be chained. */ }, { key: 'maxExpansions', value: function maxExpansions(limit) { this._queryOpts.max_expansions = limit; return this; } /** * Sets the rewrite method. Valid values are: * - `constant_score` - tries to pick the best constant-score rewrite * method based on term and document counts from the query. * Synonyms - `constant_score_auto`, `constant_score_filter` * * - `scoring_boolean` - translates each term into boolean should and * keeps the scores as computed by the query * * - `constant_score_boolean` - same as `scoring_boolean`, expect no scores * are computed. * * - `constant_score_filter` - first creates a private Filter, by visiting * each term in sequence and marking all docs for that term * * - `top_terms_boost_N` - first translates each term into boolean should * and scores are only computed as the boost using the top N * scoring terms. Replace N with an integer value. * * - `top_terms_N` - first translates each term into boolean should * and keeps the scores as computed by the query. Only the top N * scoring terms are used. Replace N with an integer value. * * Default is `constant_score`. * * This is an advanced option, use with care. * * Note: The deprecated multi term rewrite parameters `constant_score_auto`, * `constant_score_filter` (synonyms for `constant_score`) have been removed * in elasticsearch 6.0. * * @param {string} method The rewrite method as a string. * @returns {MultiMatchQuery} returns `this` so that calls can be chained. * @throws {Error} If the given `rewrite` method is not valid. */ }, { key: 'rewrite', value: function rewrite(method) { validateRewiteMethod(method, 'rewrite', ES_REF_URL); this._queryOpts.rewrite = method; return this; } /** * Sets the fuzzy rewrite method. Valid values are: * - `constant_score` - tries to pick the best constant-score rewrite * method based on term and document counts from the query. * Synonyms - `constant_score_auto`, `constant_score_filter` * * - `scoring_boolean` - translates each term into boolean should and * keeps the scores as computed by the query * * - `constant_score_boolean` - same as `scoring_boolean`, expect no scores * are computed. * * - `constant_score_filter` - first creates a private Filter, by visiting * each term in sequence and marking all docs for that term * * - `top_terms_boost_N` - first translates each term into boolean should * and scores are only computed as the boost using the top N * scoring terms. Replace N with an integer value. * * - `top_terms_N` - first translates each term into boolean should * and keeps the scores as computed by the query. Only the top N * scoring terms are used. Replace N with an integer value. * * Default is `constant_score`. * * This is an advanced option, use with care. * * Note: The deprecated multi term rewrite parameters `constant_score_auto`, * `constant_score_filter` (synonyms for `constant_score`) have been removed * in elasticsearch 6.0. * * @param {string} method The rewrite method as a string. * @returns {MultiMatchQuery} returns `this` so that calls can be chained. * @throws {Error} If the given `fuzzy_rewrite` method is not valid. */ }, { key: 'fuzzyRewrite', value: function fuzzyRewrite(method) { validateRewiteMethod(method, 'fuzzy_rewrite', ES_REF_URL); this._queryOpts.fuzzy_rewrite = method; return this; } /** * If the analyzer used removes all tokens in a query like a `stop` filter does, * the default behavior is to match no documents at all. In order to change that * the `zero_terms_query` option can be used, which accepts `none` (default) and `all` * which corresponds to a `match_all` query. * * @param {string} behavior A no match action, `all` or `none`. Default is `none`. * @returns {MultiMatchQuery} returns `this` so that calls can be chained. */ }, { key: 'zeroTermsQuery', value: function zeroTermsQuery(behavior) { if (isNil(behavior)) invalidBehaviorParam(behavior); var behaviorLower = behavior.toLowerCase(); if (behaviorLower !== 'all' && behaviorLower !== 'none') { invalidBehaviorParam(behavior); } this._queryOpts.zero_terms_query = behavior; return this; } /** * Allows specifying an absolute or relative document frequency where high frequency * terms are moved into an optional subquery and are only scored if one of the * low frequency (below the cutoff) terms in the case of an `or` operator or * all of the low frequency terms in the case of an `and` operator match. * * @param {number} frequency It can either be relative to the total number of documents * if in the range `[0..1)` or absolute if greater or equal to `1.0`. * @returns {MultiMatchQuery} returns `this` so that calls can be chained. */ }, { key: 'cutoffFrequency', value: function cutoffFrequency(frequency) { this._queryOpts.cutoff_frequency = frequency; return this; } }]); return MultiMatchQuery; }(FullTextQueryBase); module.exports = MultiMatchQuery;