public void testCrossFieldMultiMatchQuery() throws IOException { QueryShardContext queryShardContext = indexService.newQueryShardContext( randomInt(20), null, () -> { throw new UnsupportedOperationException(); }); queryShardContext.setAllowUnmappedFields(true); Query parsedQuery = multiMatchQuery("banon").field("name.first", 2).field("name.last", 3).field("foobar").type(MultiMatchQueryBuilder.Type.CROSS_FIELDS).toQuery(queryShardContext); try (Engine.Searcher searcher = indexService.getShard(0).acquireSearcher("test")) { Query rewrittenQuery = searcher.searcher().rewrite(parsedQuery); BooleanQuery.Builder expected = new BooleanQuery.Builder(); expected.add(new TermQuery(new Term("foobar", "banon")), BooleanClause.Occur.SHOULD); Query tq1 = new BoostQuery(new TermQuery(new Term("name.first", "banon")), 2); Query tq2 = new BoostQuery(new TermQuery(new Term("name.last", "banon")), 3); expected.add(new DisjunctionMaxQuery(Arrays.<Query>asList(tq1, tq2), 0f), BooleanClause.Occur.SHOULD); assertEquals(expected.build(), rewrittenQuery); } }
public static String getMatchType(@Nullable String matchType, DataType columnType) { if (matchType == null) { return defaultMatchType(columnType); } if (columnType.equals(DataTypes.STRING)) { try { MultiMatchQueryBuilder.Type.parse(matchType, ParseFieldMatcher.STRICT); return matchType; } catch (ElasticsearchParseException e) { throw new IllegalArgumentException(String.format(Locale.ENGLISH, "invalid MATCH type '%s' for type '%s'", matchType, columnType), e); } } else if (columnType.equals(DataTypes.GEO_SHAPE)) { if (!SUPPORTED_GEO_MATCH_TYPES.contains(matchType)) { throw new IllegalArgumentException(String.format(Locale.ENGLISH, "invalid MATCH type '%s' for type '%s', valid types are: [%s]", matchType, columnType, Joiner.on(",").join(SUPPORTED_GEO_MATCH_TYPES))); } return matchType; } throw new IllegalArgumentException("No match type for dataType: " + columnType); }
private static void raiseIllegalOptions(MultiMatchQueryBuilder.Type matchType, Map options) { List<String> unknownOptions = new ArrayList<>(); List<String> invalidOptions = new ArrayList<>(); for (Object o : options.keySet()) { assert o instanceof String; if (!SUPPORTED_OPTIONS.contains(o)) { unknownOptions.add((String) o); } else { invalidOptions.add((String) o); } } if (!unknownOptions.isEmpty()) { throw new IllegalArgumentException(String.format(Locale.ENGLISH, "match predicate doesn't support any of the given options: %s", Joiner.on(", ").join(unknownOptions))); } else { throw new IllegalArgumentException(String.format(Locale.ENGLISH, "match predicate option(s) \"%s\" cannot be used with matchType \"%s\"", Joiner.on(", ").join(invalidOptions), matchType.name().toLowerCase(Locale.ENGLISH) )); } }
public MatchQueryBuilder(MapperService mapperService, IndexCache indexCache, @Nullable BytesRef matchType, @Nullable Map options) throws IOException { this.mapperService = mapperService; this.indexCache = indexCache; if (matchType == null) { this.matchType = MultiMatchQueryBuilder.Type.BEST_FIELDS; } else { this.matchType = SUPPORTED_TYPES.get(matchType); if (this.matchType == null) { throw illegalMatchType(BytesRefs.toString(matchType)); } } this.options = OptionParser.parse(this.matchType, options); }
public Query parse(MultiMatchQueryBuilder.Type type, Map<String, Float> fieldNames, Object value, String minimumShouldMatch) throws IOException { if (fieldNames.size() == 1) { Map.Entry<String, Float> fieldBoost = fieldNames.entrySet().iterator().next(); Float boostValue = fieldBoost.getValue(); return parseAndApply(type.matchQueryType(), fieldBoost.getKey(), value, minimumShouldMatch, boostValue); } final float tieBreaker = groupTieBreaker == null ? type.tieBreaker() : groupTieBreaker; switch (type) { case PHRASE: case PHRASE_PREFIX: case BEST_FIELDS: case MOST_FIELDS: queryBuilder = new QueryBuilder(tieBreaker); break; case CROSS_FIELDS: queryBuilder = new CrossFieldsQueryBuilder(tieBreaker); break; default: throw new IllegalStateException("No such type: " + type); } final List<? extends Query> queries = queryBuilder.buildGroupedQueries(type, fieldNames, value, minimumShouldMatch); return queryBuilder.combineGrouped(queries); }
@Test public void testForClient() throws Exception { /** * @see <a href='https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-multi-match-query.html'></a> * MultiMatchQuery依赖于match query ,也就是其核心是基于MatchQuery构建的 * */ MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("elasticsearch match query","title", "descrption"); multiMatchQueryBuilder.analyzer("standard"); multiMatchQueryBuilder.cutoffFrequency(0.001f); multiMatchQueryBuilder.field("title",20); multiMatchQueryBuilder.fuzziness(Fuzziness.TWO); multiMatchQueryBuilder.maxExpansions(100); multiMatchQueryBuilder.prefixLength(10); multiMatchQueryBuilder.tieBreaker(20); multiMatchQueryBuilder.type(MultiMatchQueryBuilder.Type.BEST_FIELDS); multiMatchQueryBuilder.boost(20); SearchResponse searchResponse = client.prepareSearch() .setIndices("blogs") .setTypes("blog") .setQuery(multiMatchQueryBuilder) .execute() .actionGet(); }
/** * http://blog.csdn.net/xiaohulunb/article/details/37877435 */ public static <Goods> Pagination<Goods> goodSearch(GoodsSearchCondition condition, String sortField, boolean desc, int from, int size) { String value = condition.getGoodsName(); if (Pinyin4jUtil.isContainChinese(condition.getGoodsName())) { MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(value, "categoryName1", "categoryName2", "categoryName3", "goodsName", "goodsSkuAttr"); multiMatchQueryBuilder.field("categoryName1", 0.8f); multiMatchQueryBuilder.field("categoryName2", 1f); multiMatchQueryBuilder.field("categoryName3", 1.5f); multiMatchQueryBuilder.field("goodsName", 2f); multiMatchQueryBuilder.field("goodsSkuAttr", 0.8f); Pagination<Goods> goodsPagination = search(multiMatchQueryBuilder, IndexType.GOODS, sortField, desc, from, size); if (!CollectionUtils.isEmpty(goodsPagination.getDataList())) { return goodsPagination; } } return boolSearch(sortField, desc, from, size, StringUtils.lowerCase(value)); }
private QueryBuilder buildQueryBuilder(ElasticsearchSearchOption option) { ElasticsearchSearchOption.Operator op = option.getOperator(); MultiMatchQueryBuilder query = multiMatchQuery( option.getKeyword(), option.getSearchFields().stream().toArray(String[]::new)); if (op != null && ElasticsearchSearchOption.Operator.AND == op) { query = query.operator(MatchQueryBuilder.Operator.AND); } if (option.getOptionalSearchConditions().isEmpty()) { return query; } else { BoolQueryBuilder q = boolQuery().must(query); option.getOptionalSearchConditions().forEach((k, v) -> { q.must(matchQuery(k, v)); }); return q; } }
public static QueryBuilder simpleQueryBuilder(String q) { if (q.equals("yacyall")) return new MatchAllQueryBuilder(); final MultiMatchQueryBuilder qb = QueryBuilders .multiMatchQuery(q) .operator(Operator.AND) .zeroTermsQuery(ZeroTermsQuery.ALL); QUERY_DEFAULT_FIELDS.forEach((mapping, boost) -> qb.field(mapping.getSolrFieldName(), boost)); return qb; }
public Query parse(MultiMatchQueryBuilder.Type type, Map<String, Float> fieldNames, Object value, String minimumShouldMatch) throws IOException { Query result; if (fieldNames.size() == 1) { Map.Entry<String, Float> fieldBoost = fieldNames.entrySet().iterator().next(); Float boostValue = fieldBoost.getValue(); result = parseAndApply(type.matchQueryType(), fieldBoost.getKey(), value, minimumShouldMatch, boostValue); } else { final float tieBreaker = groupTieBreaker == null ? type.tieBreaker() : groupTieBreaker; switch (type) { case PHRASE: case PHRASE_PREFIX: case BEST_FIELDS: case MOST_FIELDS: queryBuilder = new QueryBuilder(tieBreaker); break; case CROSS_FIELDS: queryBuilder = new CrossFieldsQueryBuilder(tieBreaker); break; default: throw new IllegalStateException("No such type: " + type); } final List<? extends Query> queries = queryBuilder.buildGroupedQueries(type, fieldNames, value, minimumShouldMatch); result = queryBuilder.combineGrouped(queries); } assert result != null; return result; }
public List<Query> buildGroupedQueries(MultiMatchQueryBuilder.Type type, Map<String, Float> fieldNames, Object value, String minimumShouldMatch) throws IOException{ List<Query> queries = new ArrayList<>(); for (String fieldName : fieldNames.keySet()) { Float boostValue = fieldNames.get(fieldName); Query query = parseGroup(type.matchQueryType(), fieldName, boostValue, value, minimumShouldMatch); if (query != null) { queries.add(query); } } return queries; }
public void testMultiMatchPrefixWithAllField() throws IOException { QueryShardContext queryShardContext = indexService.newQueryShardContext( randomInt(20), null, () -> { throw new UnsupportedOperationException(); }); queryShardContext.setAllowUnmappedFields(true); Query parsedQuery = multiMatchQuery("foo").field("_all").type(MultiMatchQueryBuilder.Type.PHRASE_PREFIX).toQuery(queryShardContext); assertThat(parsedQuery, instanceOf(MultiPhrasePrefixQuery.class)); assertThat(parsedQuery.toString(), equalTo("_all:\"foo*\"")); }
public void testMultiMatchCrossFieldsWithSynonyms() throws IOException { QueryShardContext queryShardContext = indexService.newQueryShardContext( randomInt(20), null, () -> { throw new UnsupportedOperationException(); }); // check that synonym query is used for a single field Query parsedQuery = multiMatchQuery("quick").field("name.first") .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS).toQuery(queryShardContext); Term[] terms = new Term[2]; terms[0] = new Term("name.first", "quick"); terms[1] = new Term("name.first", "fast"); Query expectedQuery = new SynonymQuery(terms); assertThat(parsedQuery, equalTo(expectedQuery)); // check that blended term query is used for multiple fields parsedQuery = multiMatchQuery("quick").field("name.first").field("name.last") .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS).toQuery(queryShardContext); terms = new Term[4]; terms[0] = new Term("name.first", "quick"); terms[1] = new Term("name.first", "fast"); terms[2] = new Term("name.last", "quick"); terms[3] = new Term("name.last", "fast"); float[] boosts = new float[4]; Arrays.fill(boosts, 1.0f); expectedQuery = BlendedTermQuery.dismaxBlendedQuery(terms, boosts, 1.0f); assertThat(parsedQuery, equalTo(expectedQuery)); }
public static ParsedOptions parse(MultiMatchQueryBuilder.Type matchType, @Nullable Map options) throws IllegalArgumentException { if (options == null) { options = Collections.emptyMap(); } else { // need a copy. Otherwise manipulations on a shared option will lead to strange race conditions. options = new HashMap(options); } ParsedOptions parsedOptions = new ParsedOptions( floatValue(options, OPTIONS.BOOST, null), analyzer(options.remove(OPTIONS.ANALYZER)), zeroTermsQuery(options.remove(OPTIONS.ZERO_TERMS_QUERY)), intValue(options, OPTIONS.MAX_EXPANSIONS, FuzzyQuery.defaultMaxExpansions), fuzziness(options.remove(OPTIONS.FUZZINESS)), intValue(options, OPTIONS.PREFIX_LENGTH, FuzzyQuery.defaultPrefixLength), transpositions(options.remove(OPTIONS.FUZZY_TRANSPOSITIONS)) ); switch (matchType.matchQueryType()) { case BOOLEAN: parsedOptions.commonTermsCutoff(floatValue(options, OPTIONS.CUTOFF_FREQUENCY, null)); parsedOptions.operator(operator(options.remove(OPTIONS.OPERATOR))); parsedOptions.minimumShouldMatch(minimumShouldMatch(options.remove(OPTIONS.MINIMUM_SHOULD_MATCH))); break; case PHRASE: parsedOptions.phraseSlop(intValue(options, OPTIONS.SLOP, 0)); parsedOptions.tieBreaker(floatValue(options, OPTIONS.TIE_BREAKER, null)); break; case PHRASE_PREFIX: parsedOptions.phraseSlop(intValue(options, OPTIONS.SLOP, 0)); parsedOptions.tieBreaker(floatValue(options, OPTIONS.TIE_BREAKER, null)); parsedOptions.rewrite(rewrite(options.remove(OPTIONS.REWRITE))); break; } if (!options.isEmpty()) { raiseIllegalOptions(matchType, options); } return parsedOptions; }
/** * Method of creating semantic query based on Threshold * * @param input regular query * @param T threshold raning from 0 to 1 * @param query_operator query mode * @return a multiMatch query builder */ public BoolQueryBuilder createSemQuery(String input, double T, String query_operator) { Map<String, Double> selected_Map = getRelatedTermsByT(input, T); selected_Map.put(input, (double) 1); String fieldsList[] = { "Dataset-Metadata", "Dataset-ShortName", "Dataset-LongName", "DatasetParameter-Topic", "DatasetParameter-VariableDetail", "DatasetParameter-Category", "DatasetParameter-Variable", "DatasetParameter-Term", "DatasetSource-Source-LongName", "DatasetSource-Source-LongName-Full", "DatasetSource-Source-ShortName", "DatasetSource-Source-ShortName-Full", "DatasetSource-Sensor-LongName", "DatasetSource-Sensor-LongName-Full", "DatasetSource-Sensor-ShortName", "DatasetSource-Sensor-ShortName-Full" }; BoolQueryBuilder qb = new BoolQueryBuilder(); for (Entry<String, Double> entry : selected_Map.entrySet()) { if (query_operator.toLowerCase().trim().equals("phrase")) { qb.should(QueryBuilders.multiMatchQuery(entry.getKey(), fieldsList).boost(entry.getValue().floatValue()).type(MultiMatchQueryBuilder.Type.PHRASE).tieBreaker((float) 0.5)); // when // set // to // 1.0, // it // would // be // equal // to // "most // fields" // query } else if (query_operator.toLowerCase().trim().equals("and")) { qb.should(QueryBuilders.multiMatchQuery(entry.getKey(), fieldsList).boost(entry.getValue().floatValue()).operator(MatchQueryBuilder.DEFAULT_OPERATOR.AND).tieBreaker((float) 0.5)); } else { qb.should(QueryBuilders.multiMatchQuery(entry.getKey(), fieldsList).boost(entry.getValue().floatValue()).operator(MatchQueryBuilder.DEFAULT_OPERATOR.OR).tieBreaker((float) 0.5)); } } // LOG.info(qb.toString()); return qb; }
/** * Private method to build a multi match query. * * @param searchTerm the term on which to search * @param queryType the query type for this multi match query * @param queryBoost the query boost for this multi match query * @param fieldType the field type for this multi match query * @param match the set of match fields that are to be searched upon in the index search * * @return the multi match query */ private MultiMatchQueryBuilder buildMultiMatchQuery(final String searchTerm, final MultiMatchQueryBuilder.Type queryType, final float queryBoost, final String fieldType, Set<String> match) { MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(searchTerm).type(queryType); multiMatchQueryBuilder.boost(queryBoost); if (fieldType.equals(FIELD_TYPE_STEMMED)) { // Get the configured value for 'stemmed' fields and their respective boosts if any String stemmedFieldsValue = configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_SEARCHABLE_FIELDS_STEMMED); // build the query buildMultiMatchQueryWithBoosts(multiMatchQueryBuilder, stemmedFieldsValue, match); } if (fieldType.equals(FIELD_TYPE_NGRAMS)) { // Get the configured value for 'ngrams' fields and their respective boosts if any String ngramsFieldsValue = configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_SEARCHABLE_FIELDS_NGRAMS); // build the query buildMultiMatchQueryWithBoosts(multiMatchQueryBuilder, ngramsFieldsValue, match); } if (fieldType.equals(FIELD_TYPE_SHINGLES)) { // Get the configured value for 'shingles' fields and their respective boosts if any String shinglesFieldsValue = configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_SEARCHABLE_FIELDS_SHINGLES); // build the query buildMultiMatchQueryWithBoosts(multiMatchQueryBuilder, shinglesFieldsValue, match); } return multiMatchQueryBuilder; }
/** * Private method to build a multimatch query based on a given set of fields and boost values in json format * * @param multiMatchQueryBuilder A {@link MultiMatchQueryBuilder} which should be constructed * @param fieldsBoostsJsonString A json formatted String which contains individual fields and their boost values * @param match the set of match fields that are to be searched upon in the index search */ private void buildMultiMatchQueryWithBoosts(MultiMatchQueryBuilder multiMatchQueryBuilder, String fieldsBoostsJsonString, Set<String> match) { try { @SuppressWarnings("unchecked") final Map<String, String> fieldsBoostsMap = jsonHelper.unmarshallJsonToObject(Map.class, fieldsBoostsJsonString); // This additional step is needed because trying to cast an unmarshalled json to a Map of anything other than String key-value pairs won't work final Map<String, Float> fieldsBoosts = new HashMap<>(); // If the match column is included if (match != null && match.contains(MATCH_COLUMN)) { // Add only the column.name and schemaColumn.name fields to the fieldsBoosts map fieldsBoostsMap.forEach((field, boostValue) -> { if (field.contains(COLUMNS_NAME_FIELD) || field.contains(SCHEMA_COLUMNS_NAME_FIELD)) { fieldsBoosts.put(field, Float.parseFloat(boostValue)); } }); } else { fieldsBoostsMap.forEach((field, boostValue) -> fieldsBoosts.put(field, Float.parseFloat(boostValue))); } // Set the fields and their respective boosts to the multi-match query multiMatchQueryBuilder.fields(fieldsBoosts); } catch (IOException e) { LOGGER.warn("Could not parse the configured JSON value for ngrams fields: {}", ConfigurationValue.ELASTICSEARCH_SEARCHABLE_FIELDS_NGRAMS, e); } }
public void testPercolatorSpecificQueries() throws Exception { createIndex("test", client().admin().indices().prepareCreate("test") .addMapping("type", "field1", "type=text", "field2", "type=text") .addMapping("queries", "query", "type=percolator") ); client().prepareIndex("test", "queries", "1") .setSource(jsonBuilder().startObject().field("query", commonTermsQuery("field1", "quick brown fox")).endObject()) .get(); client().prepareIndex("test", "queries", "2") .setSource(jsonBuilder().startObject().field("query", multiMatchQuery("quick brown fox", "field1", "field2") .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)).endObject()) .get(); client().prepareIndex("test", "queries", "3") .setSource(jsonBuilder().startObject().field("query", spanNearQuery(spanTermQuery("field1", "quick"), 0) .addClause(spanTermQuery("field1", "brown")) .addClause(spanTermQuery("field1", "fox")) .inOrder(true) ).endObject()) .get(); client().admin().indices().prepareRefresh().get(); client().prepareIndex("test", "queries", "4") .setSource(jsonBuilder().startObject().field("query", spanNotQuery( spanNearQuery(spanTermQuery("field1", "quick"), 0) .addClause(spanTermQuery("field1", "brown")) .addClause(spanTermQuery("field1", "fox")) .inOrder(true), spanNearQuery(spanTermQuery("field1", "the"), 0) .addClause(spanTermQuery("field1", "lazy")) .addClause(spanTermQuery("field1", "dog")) .inOrder(true)).dist(2) ).endObject()) .get(); // doesn't match client().prepareIndex("test", "queries", "5") .setSource(jsonBuilder().startObject().field("query", spanNotQuery( spanNearQuery(spanTermQuery("field1", "quick"), 0) .addClause(spanTermQuery("field1", "brown")) .addClause(spanTermQuery("field1", "fox")) .inOrder(true), spanNearQuery(spanTermQuery("field1", "the"), 0) .addClause(spanTermQuery("field1", "lazy")) .addClause(spanTermQuery("field1", "dog")) .inOrder(true)).dist(3) ).endObject()) .get(); client().admin().indices().prepareRefresh().get(); BytesReference source = jsonBuilder().startObject() .field("field1", "the quick brown fox jumps over the lazy dog") .field("field2", "the quick brown fox falls down into the well") .endObject().bytes(); SearchResponse response = client().prepareSearch() .setQuery(new PercolateQueryBuilder("query", "type", source, XContentType.JSON)) .addSort("_uid", SortOrder.ASC) .get(); assertHitCount(response, 4); assertThat(response.getHits().getAt(0).getId(), equalTo("1")); assertThat(response.getHits().getAt(0).getScore(), equalTo(Float.NaN)); assertThat(response.getHits().getAt(1).getId(), equalTo("2")); assertThat(response.getHits().getAt(1).getScore(), equalTo(Float.NaN)); assertThat(response.getHits().getAt(2).getId(), equalTo("3")); assertThat(response.getHits().getAt(2).getScore(), equalTo(Float.NaN)); assertThat(response.getHits().getAt(3).getId(), equalTo("4")); assertThat(response.getHits().getAt(3).getScore(), equalTo(Float.NaN)); }
private void registerQueryParsers(List<SearchPlugin> plugins) { registerQuery(new QuerySpec<>(MatchQueryBuilder.NAME, MatchQueryBuilder::new, MatchQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(MatchPhraseQueryBuilder.NAME, MatchPhraseQueryBuilder::new, MatchPhraseQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(MatchPhrasePrefixQueryBuilder.NAME, MatchPhrasePrefixQueryBuilder::new, MatchPhrasePrefixQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(MultiMatchQueryBuilder.NAME, MultiMatchQueryBuilder::new, MultiMatchQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(NestedQueryBuilder.NAME, NestedQueryBuilder::new, NestedQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(HasChildQueryBuilder.NAME, HasChildQueryBuilder::new, HasChildQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(HasParentQueryBuilder.NAME, HasParentQueryBuilder::new, HasParentQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(DisMaxQueryBuilder.NAME, DisMaxQueryBuilder::new, DisMaxQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(IdsQueryBuilder.NAME, IdsQueryBuilder::new, IdsQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(MatchAllQueryBuilder.NAME, MatchAllQueryBuilder::new, MatchAllQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(QueryStringQueryBuilder.NAME, QueryStringQueryBuilder::new, QueryStringQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(BoostingQueryBuilder.NAME, BoostingQueryBuilder::new, BoostingQueryBuilder::fromXContent)); BooleanQuery.setMaxClauseCount(INDICES_MAX_CLAUSE_COUNT_SETTING.get(settings)); registerQuery(new QuerySpec<>(BoolQueryBuilder.NAME, BoolQueryBuilder::new, BoolQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(TermQueryBuilder.NAME, TermQueryBuilder::new, TermQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(TermsQueryBuilder.NAME, TermsQueryBuilder::new, TermsQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(FuzzyQueryBuilder.NAME, FuzzyQueryBuilder::new, FuzzyQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(RegexpQueryBuilder.NAME, RegexpQueryBuilder::new, RegexpQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(RangeQueryBuilder.NAME, RangeQueryBuilder::new, RangeQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(PrefixQueryBuilder.NAME, PrefixQueryBuilder::new, PrefixQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(WildcardQueryBuilder.NAME, WildcardQueryBuilder::new, WildcardQueryBuilder::fromXContent)); registerQuery( new QuerySpec<>(ConstantScoreQueryBuilder.NAME, ConstantScoreQueryBuilder::new, ConstantScoreQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(SpanTermQueryBuilder.NAME, SpanTermQueryBuilder::new, SpanTermQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(SpanNotQueryBuilder.NAME, SpanNotQueryBuilder::new, SpanNotQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(SpanWithinQueryBuilder.NAME, SpanWithinQueryBuilder::new, SpanWithinQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(SpanContainingQueryBuilder.NAME, SpanContainingQueryBuilder::new, SpanContainingQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(FieldMaskingSpanQueryBuilder.NAME, FieldMaskingSpanQueryBuilder::new, FieldMaskingSpanQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(SpanFirstQueryBuilder.NAME, SpanFirstQueryBuilder::new, SpanFirstQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(SpanNearQueryBuilder.NAME, SpanNearQueryBuilder::new, SpanNearQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(SpanOrQueryBuilder.NAME, SpanOrQueryBuilder::new, SpanOrQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(MoreLikeThisQueryBuilder.NAME, MoreLikeThisQueryBuilder::new, MoreLikeThisQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(WrapperQueryBuilder.NAME, WrapperQueryBuilder::new, WrapperQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(CommonTermsQueryBuilder.NAME, CommonTermsQueryBuilder::new, CommonTermsQueryBuilder::fromXContent)); registerQuery( new QuerySpec<>(SpanMultiTermQueryBuilder.NAME, SpanMultiTermQueryBuilder::new, SpanMultiTermQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(FunctionScoreQueryBuilder.NAME, FunctionScoreQueryBuilder::new, FunctionScoreQueryBuilder::fromXContent)); registerQuery( new QuerySpec<>(SimpleQueryStringBuilder.NAME, SimpleQueryStringBuilder::new, SimpleQueryStringBuilder::fromXContent)); registerQuery(new QuerySpec<>(TypeQueryBuilder.NAME, TypeQueryBuilder::new, TypeQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(ScriptQueryBuilder.NAME, ScriptQueryBuilder::new, ScriptQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(GeoDistanceQueryBuilder.NAME, GeoDistanceQueryBuilder::new, GeoDistanceQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(GeoBoundingBoxQueryBuilder.NAME, GeoBoundingBoxQueryBuilder::new, GeoBoundingBoxQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(GeoPolygonQueryBuilder.NAME, GeoPolygonQueryBuilder::new, GeoPolygonQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(ExistsQueryBuilder.NAME, ExistsQueryBuilder::new, ExistsQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(MatchNoneQueryBuilder.NAME, MatchNoneQueryBuilder::new, MatchNoneQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(ParentIdQueryBuilder.NAME, ParentIdQueryBuilder::new, ParentIdQueryBuilder::fromXContent)); if (ShapesAvailability.JTS_AVAILABLE && ShapesAvailability.SPATIAL4J_AVAILABLE) { registerQuery(new QuerySpec<>(GeoShapeQueryBuilder.NAME, GeoShapeQueryBuilder::new, GeoShapeQueryBuilder::fromXContent)); } registerFromPlugin(plugins, SearchPlugin::getQueries, this::registerQuery); }
public void testMultiMatchQuery() throws Exception { createIndex("test"); indexRandom(true, client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value4", "field3", "value3"), client().prepareIndex("test", "type1", "2").setSource("field1", "value2", "field2", "value5", "field3", "value2"), client().prepareIndex("test", "type1", "3").setSource("field1", "value3", "field2", "value6", "field3", "value1") ); MultiMatchQueryBuilder builder = multiMatchQuery("value1 value2 value4", "field1", "field2"); SearchResponse searchResponse = client().prepareSearch().setQuery(builder) .addAggregation(AggregationBuilders.terms("field1").field("field1.keyword")).get(); assertHitCount(searchResponse, 2L); // this uses dismax so scores are equal and the order can be arbitrary assertSearchHits(searchResponse, "1", "2"); builder.useDisMax(false); searchResponse = client().prepareSearch() .setQuery(builder) .get(); assertHitCount(searchResponse, 2L); assertSearchHits(searchResponse, "1", "2"); client().admin().indices().prepareRefresh("test").get(); builder = multiMatchQuery("value1", "field1", "field2") .operator(Operator.AND); // Operator only applies on terms inside a field! Fields are always OR-ed together. searchResponse = client().prepareSearch() .setQuery(builder) .get(); assertHitCount(searchResponse, 1L); assertFirstHit(searchResponse, hasId("1")); refresh(); builder = multiMatchQuery("value1", "field1").field("field3", 1.5f) .operator(Operator.AND); // Operator only applies on terms inside a field! Fields are always OR-ed together. searchResponse = client().prepareSearch().setQuery(builder).get(); assertHitCount(searchResponse, 2L); assertSearchHits(searchResponse, "3", "1"); client().admin().indices().prepareRefresh("test").get(); builder = multiMatchQuery("value1").field("field1").field("field3", 1.5f) .operator(Operator.AND); // Operator only applies on terms inside a field! Fields are always OR-ed together. searchResponse = client().prepareSearch().setQuery(builder).get(); assertHitCount(searchResponse, 2L); assertSearchHits(searchResponse, "3", "1"); // Test lenient client().prepareIndex("test", "type1", "3").setSource("field1", "value7", "field2", "value8", "field4", 5).get(); refresh(); builder = multiMatchQuery("value1", "field1", "field2", "field4"); assertFailures(client().prepareSearch().setQuery(builder), RestStatus.BAD_REQUEST, containsString("NumberFormatException[For input string: \"value1\"]")); builder.lenient(true); searchResponse = client().prepareSearch().setQuery(builder).get(); assertHitCount(searchResponse, 1L); assertFirstHit(searchResponse, hasId("1")); }
public void testMultiMatchQueryMinShouldMatch() { createIndex("test"); client().prepareIndex("test", "type1", "1").setSource("field1", new String[]{"value1", "value2", "value3"}).get(); client().prepareIndex("test", "type1", "2").setSource("field2", "value1").get(); refresh(); MultiMatchQueryBuilder multiMatchQuery = multiMatchQuery("value1 value2 foo", "field1", "field2"); multiMatchQuery.useDisMax(true); multiMatchQuery.minimumShouldMatch("70%"); SearchResponse searchResponse = client().prepareSearch() .setQuery(multiMatchQuery) .get(); assertHitCount(searchResponse, 1L); assertFirstHit(searchResponse, hasId("1")); multiMatchQuery.minimumShouldMatch("30%"); searchResponse = client().prepareSearch().setQuery(multiMatchQuery).get(); assertHitCount(searchResponse, 2L); assertFirstHit(searchResponse, hasId("1")); assertSecondHit(searchResponse, hasId("2")); multiMatchQuery.useDisMax(false); multiMatchQuery.minimumShouldMatch("70%"); searchResponse = client().prepareSearch().setQuery(multiMatchQuery).get(); assertHitCount(searchResponse, 1L); assertFirstHit(searchResponse, hasId("1")); multiMatchQuery.minimumShouldMatch("30%"); searchResponse = client().prepareSearch().setQuery(multiMatchQuery).get(); assertHitCount(searchResponse, 2L); assertFirstHit(searchResponse, hasId("1")); assertSecondHit(searchResponse, hasId("2")); multiMatchQuery = multiMatchQuery("value1 value2 bar", "field1"); multiMatchQuery.minimumShouldMatch("100%"); searchResponse = client().prepareSearch().setQuery(multiMatchQuery).get(); assertHitCount(searchResponse, 0L); multiMatchQuery.minimumShouldMatch("70%"); searchResponse = client().prepareSearch().setQuery(multiMatchQuery).get(); assertHitCount(searchResponse, 1L); assertFirstHit(searchResponse, hasId("1")); // Min should match > # optional clauses returns no docs. multiMatchQuery = multiMatchQuery("value1 value2 value3", "field1", "field2"); multiMatchQuery.minimumShouldMatch("4"); searchResponse = client().prepareSearch().setQuery(multiMatchQuery).get(); assertHitCount(searchResponse, 0L); }
public void testSingleField() throws NoSuchFieldException, IllegalAccessException { SearchResponse searchResponse = client().prepareSearch("test") .setQuery(randomizeType(multiMatchQuery("15", "skill"))).get(); assertNoFailures(searchResponse); assertFirstHit(searchResponse, hasId("theone")); searchResponse = client().prepareSearch("test") .setQuery(randomizeType(multiMatchQuery("15", "skill", "int-field")).analyzer("category")).get(); assertNoFailures(searchResponse); assertFirstHit(searchResponse, hasId("theone")); String[] fields = { "full_name", "first_name", "last_name", "last_name_phrase", "first_name_phrase", "category_phrase", "category", "missing_field", "missing_fields*" }; String[] query = {"marvel","hero", "captain", "america", "15", "17", "1", "5", "ultimate", "Man", "marvel", "wolferine", "ninja"}; // check if it's equivalent to a match query. int numIters = scaledRandomIntBetween(10, 100); for (int i = 0; i < numIters; i++) { String field = RandomPicks.randomFrom(random(), fields); int numTerms = randomIntBetween(1, query.length); StringBuilder builder = new StringBuilder(); for (int j = 0; j < numTerms; j++) { builder.append(RandomPicks.randomFrom(random(), query)).append(" "); } MultiMatchQueryBuilder multiMatchQueryBuilder = randomizeType(multiMatchQuery(builder.toString(), field)); SearchResponse multiMatchResp = client().prepareSearch("test") // _uid sort field is a tie, in case hits have the same score, // the hits will be sorted the same consistently .addSort("_score", SortOrder.DESC) .addSort("_uid", SortOrder.ASC) .setQuery(multiMatchQueryBuilder).get(); MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(field, builder.toString()); if (multiMatchQueryBuilder.getType() != null) { matchQueryBuilder.type(MatchQuery.Type.valueOf(multiMatchQueryBuilder.getType().matchQueryType().toString())); } SearchResponse matchResp = client().prepareSearch("test") // _uid tie sort .addSort("_score", SortOrder.DESC) .addSort("_uid", SortOrder.ASC) .setQuery(matchQueryBuilder).get(); assertThat("field: " + field + " query: " + builder.toString(), multiMatchResp.getHits().getTotalHits(), equalTo(matchResp.getHits().getTotalHits())); SearchHits hits = multiMatchResp.getHits(); if (field.startsWith("missing")) { assertEquals(0, hits.getHits().length); } for (int j = 0; j < hits.getHits().length; j++) { assertThat(hits.getHits()[j].getScore(), equalTo(matchResp.getHits().getHits()[j].getScore())); assertThat(hits.getHits()[j].getId(), equalTo(matchResp.getHits().getHits()[j].getId())); } } }
public void testCutoffFreq() throws ExecutionException, InterruptedException { final long numDocs = client().prepareSearch("test").setSize(0) .setQuery(matchAllQuery()).get().getHits().getTotalHits(); MatchQuery.Type type = randomBoolean() ? MatchQueryBuilder.DEFAULT_TYPE : MatchQuery.Type.BOOLEAN; Float cutoffFrequency = randomBoolean() ? Math.min(1, numDocs * 1.f / between(10, 20)) : 1.f / between(10, 20); SearchResponse searchResponse = client().prepareSearch("test") .setQuery(randomizeType(multiMatchQuery("marvel hero captain america", "full_name", "first_name", "last_name", "category") .operator(Operator.OR).cutoffFrequency(cutoffFrequency))).get(); Set<String> topNIds = Sets.newHashSet("theone", "theother"); for (int i = 0; i < searchResponse.getHits().getHits().length; i++) { topNIds.remove(searchResponse.getHits().getAt(i).getId()); // very likely that we hit a random doc that has the same score so orders are random since // the doc id is the tie-breaker } assertThat(topNIds, empty()); assertThat(searchResponse.getHits().getHits()[0].getScore(), greaterThanOrEqualTo(searchResponse.getHits().getHits()[1].getScore())); cutoffFrequency = randomBoolean() ? Math.min(1, numDocs * 1.f / between(10, 20)) : 1.f / between(10, 20); searchResponse = client().prepareSearch("test") .setQuery(randomizeType(multiMatchQuery("marvel hero captain america", "full_name", "first_name", "last_name", "category") .operator(Operator.OR).useDisMax(false).cutoffFrequency(cutoffFrequency).type(type))).get(); assertFirstHit(searchResponse, anyOf(hasId("theone"), hasId("theother"))); assertThat(searchResponse.getHits().getHits()[0].getScore(), greaterThan(searchResponse.getHits().getHits()[1].getScore())); long size = searchResponse.getHits().getTotalHits(); searchResponse = client().prepareSearch("test") .setQuery(randomizeType(multiMatchQuery("marvel hero captain america", "full_name", "first_name", "last_name", "category") .operator(Operator.OR).useDisMax(false).type(type))).get(); assertFirstHit(searchResponse, anyOf(hasId("theone"), hasId("theother"))); assertThat("common terms expected to be a way smaller result set", size, lessThan(searchResponse.getHits().getTotalHits())); cutoffFrequency = randomBoolean() ? Math.min(1, numDocs * 1.f / between(10, 20)) : 1.f / between(10, 20); searchResponse = client().prepareSearch("test") .setQuery(randomizeType(multiMatchQuery("marvel hero", "full_name", "first_name", "last_name", "category") .operator(Operator.OR).cutoffFrequency(cutoffFrequency).type(type))).get(); assertFirstHit(searchResponse, hasId("theother")); searchResponse = client().prepareSearch("test") .setQuery(randomizeType(multiMatchQuery("captain america", "full_name", "first_name", "last_name", "category") .operator(Operator.AND).cutoffFrequency(cutoffFrequency).type(type))).get(); assertHitCount(searchResponse, 1L); assertFirstHit(searchResponse, hasId("theone")); searchResponse = client().prepareSearch("test") .setQuery(randomizeType(multiMatchQuery("captain america", "full_name", "first_name", "last_name", "category") .operator(Operator.AND).cutoffFrequency(cutoffFrequency).type(type))).get(); assertHitCount(searchResponse, 1L); assertFirstHit(searchResponse, hasId("theone")); searchResponse = client().prepareSearch("test") .setQuery(randomizeType(multiMatchQuery("marvel hero", "first_name", "last_name", "category") .operator(Operator.AND).cutoffFrequency(cutoffFrequency) .analyzer("category") .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS))).get(); assertHitCount(searchResponse, 1L); assertFirstHit(searchResponse, hasId("theother")); }
private static MultiMatchQueryBuilder randomizeType(MultiMatchQueryBuilder builder) { try { MultiMatchQueryBuilder.Type type = builder.getType(); if (type == null && randomBoolean()) { return builder; } if (type == null) { type = MultiMatchQueryBuilder.Type.BEST_FIELDS; } if (randomBoolean()) { builder.type(type); } else { Object oType = type; switch (type) { case BEST_FIELDS: if (randomBoolean()) { oType = MatchQuery.Type.BOOLEAN; } break; case MOST_FIELDS: if (randomBoolean()) { oType = MatchQuery.Type.BOOLEAN; } break; case CROSS_FIELDS: break; case PHRASE: if (randomBoolean()) { oType = MatchQuery.Type.PHRASE; } break; case PHRASE_PREFIX: if (randomBoolean()) { oType = MatchQuery.Type.PHRASE_PREFIX; } break; } builder.type(oType); } return builder; } catch (Exception ex) { throw new RuntimeException(ex); } }
public void testMultiMatchQueryHighlight() throws IOException { String[] highlighterTypes = new String[] {"fvh", "plain", "postings", "unified"}; XContentBuilder mapping = XContentFactory.jsonBuilder().startObject().startObject("type1") .startObject("properties") .startObject("field1") .field("type", "text") .field("index_options", "offsets") .field("term_vector", "with_positions_offsets") .endObject() .startObject("field2") .field("type", "text") .field("index_options", "offsets") .field("term_vector", "with_positions_offsets") .endObject() .endObject() .endObject().endObject(); assertAcked(prepareCreate("test").addMapping("type1", mapping)); ensureGreen(); client().prepareIndex("test", "type1") .setSource("field1", "The quick brown fox jumps over", "field2", "The quick brown fox jumps over").get(); refresh(); final int iters = scaledRandomIntBetween(20, 30); for (int i = 0; i < iters; i++) { String highlighterType = rarely() ? null : RandomPicks.randomFrom(random(), highlighterTypes); MultiMatchQueryBuilder.Type[] supportedQueryTypes; if ("postings".equals(highlighterType)) { /* * phrase_prefix is not supported by postings highlighter, as it rewrites against an empty reader, the prefix will never * match any term */ supportedQueryTypes = new MultiMatchQueryBuilder.Type[]{ MultiMatchQueryBuilder.Type.BEST_FIELDS, MultiMatchQueryBuilder.Type.CROSS_FIELDS, MultiMatchQueryBuilder.Type.MOST_FIELDS, MultiMatchQueryBuilder.Type.PHRASE}; } else { supportedQueryTypes = MultiMatchQueryBuilder.Type.values(); } MultiMatchQueryBuilder.Type matchQueryType = RandomPicks.randomFrom(random(), supportedQueryTypes); MultiMatchQueryBuilder multiMatchQueryBuilder = multiMatchQuery("the quick brown fox", "field1", "field2").type(matchQueryType); SearchSourceBuilder source = searchSource() .query(multiMatchQueryBuilder) .highlighter(highlight().highlightQuery(randomBoolean() ? multiMatchQueryBuilder : null) .highlighterType(highlighterType) .field(new Field("field1").requireFieldMatch(true).preTags("<field1>").postTags("</field1>"))); logger.info("Running multi-match type: [{}] highlight with type: [{}]", matchQueryType, highlighterType); SearchResponse searchResponse = client().search(searchRequest("test").source(source)).actionGet(); assertHitCount(searchResponse, 1L); assertHighlight(searchResponse, 0, "field1", 0, anyOf(equalTo("<field1>The quick brown fox</field1> jumps over"), equalTo("<field1>The</field1> <field1>quick</field1> <field1>brown</field1> <field1>fox</field1> jumps over"))); } }
public MultiMatchQueryBuilder multiMatchBuilder(String text, String...fields){ MultiMatchQueryBuilder q = multiMatchQuery(text, fields); queryBuilder = q; return q; }