public void testToQueryPhraseQuery() throws IOException { assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0); Query query = queryStringQuery("\"term1 term2\"") .defaultField(STRING_FIELD_NAME) .phraseSlop(3) .toQuery(createShardContext()); assertThat(query, instanceOf(DisjunctionMaxQuery.class)); DisjunctionMaxQuery disjunctionMaxQuery = (DisjunctionMaxQuery) query; assertThat(disjunctionMaxQuery.getDisjuncts().size(), equalTo(1)); assertThat(disjunctionMaxQuery.getDisjuncts().get(0), instanceOf(PhraseQuery.class)); PhraseQuery phraseQuery = (PhraseQuery)disjunctionMaxQuery.getDisjuncts().get(0); assertThat(phraseQuery.getTerms().length, equalTo(2)); assertThat(phraseQuery.getTerms()[0], equalTo(new Term(STRING_FIELD_NAME, "term1"))); assertThat(phraseQuery.getTerms()[1], equalTo(new Term(STRING_FIELD_NAME, "term2"))); assertThat(phraseQuery.getSlop(), equalTo(3)); }
public void testToQueryPhraseQueryBoostAndSlop() throws IOException { assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0); QueryStringQueryBuilder queryStringQueryBuilder = new QueryStringQueryBuilder("\"test phrase\"~2").field(STRING_FIELD_NAME, 5f); Query query = queryStringQueryBuilder.toQuery(createShardContext()); assertThat(query, instanceOf(DisjunctionMaxQuery.class)); DisjunctionMaxQuery disjunctionMaxQuery = (DisjunctionMaxQuery) query; assertThat(disjunctionMaxQuery.getDisjuncts().size(), equalTo(1)); assertThat(disjunctionMaxQuery.getDisjuncts().get(0), instanceOf(BoostQuery.class)); BoostQuery boostQuery = (BoostQuery) disjunctionMaxQuery.getDisjuncts().get(0); assertThat(boostQuery.getBoost(), equalTo(5f)); assertThat(boostQuery.getQuery(), instanceOf(PhraseQuery.class)); PhraseQuery phraseQuery = (PhraseQuery) boostQuery.getQuery(); assertThat(phraseQuery.getSlop(), Matchers.equalTo(2)); assertThat(phraseQuery.getTerms().length, equalTo(2)); }
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); } }
@Override public Query getQuery(Element e) throws ParserException { float tieBreaker = DOMUtils.getAttribute(e, "tieBreaker", 0.0f); DisjunctionMaxQuery dq = new DisjunctionMaxQuery(tieBreaker); dq.setBoost(DOMUtils.getAttribute(e, "boost", 1.0f)); NodeList nl = e.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { // all elements are disjuncts. Element queryElem = (Element) node; Query q = factory.getQuery(queryElem); dq.add(q); } } return dq; }
public Query combineGrouped(List<Query> queries) { if (queries == null || queries.isEmpty()) { return null; } if (queries.size() == 1) { return queries.get(0); } if (groupDismax) { return new DisjunctionMaxQuery(queries, tieBreaker); } else { BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder(); for (Query query : queries) { booleanQuery.add(query, BooleanClause.Occur.SHOULD); } return booleanQuery.build(); } }
@Override protected Query construct(LindenQuery lindenQuery, LindenConfig config) throws Exception { if (!lindenQuery.isSetDisMaxQuery()) { return null; } LindenDisMaxQuery disMaxQuery = lindenQuery.getDisMaxQuery(); DisjunctionMaxQuery disjunctionMaxQuery = new DisjunctionMaxQuery((float) disMaxQuery.getTie()); for (LindenQuery subLindenQuery : disMaxQuery.getQueries()) { Query query = QueryConstructor.constructQuery(subLindenQuery, config); if (query != null) { disjunctionMaxQuery.add(query); } } return disjunctionMaxQuery; }
private boolean containsClause(Query query, String field, String value, int boost, boolean fuzzy) { if(query instanceof BooleanQuery) { return containsClause((BooleanQuery)query, field, value, boost, fuzzy); } if(query instanceof DisjunctionMaxQuery) { return containsClause((DisjunctionMaxQuery)query, field, value, boost, fuzzy); } if(query instanceof TermQuery && !fuzzy) { return containsClause((TermQuery)query, field, value, boost); } if(query instanceof FuzzyQuery && fuzzy) { return containsClause((FuzzyQuery)query, field, value, boost); } return false; }
@Test public void testExtractTwoSubqueries() { Query q1 = mock(Query.class); Query q2 = mock(Query.class); DisjunctionQueryExtractor disjunctionQueryExtracotr = new DisjunctionQueryExtractor(); List<Query> disjunctQueries = new ArrayList<>(); disjunctQueries.add(q1); disjunctQueries.add(q2); DisjunctionMaxQuery disjunctionMaxQuery = new DisjunctionMaxQuery(disjunctQueries, 0.0f); List<Query> extractedQueries = new ArrayList<>(); disjunctionQueryExtracotr.extract(disjunctionMaxQuery, DEFAULT_EXTRACTORS, extractedQueries); assertEquals(2, extractedQueries.size()); assertEquals(q1, extractedQueries.get(0)); assertEquals(q2, extractedQueries.get(1)); }
@Test public void testExtractSubqueryField() { Query q1 = new TermQuery(new Term("field1", "value1")); Query q2 = new TermQuery(new Term("field2", "value2")); DisjunctionQueryExtractor disjunctionQueryExtracotr = new DisjunctionQueryExtractor(); List<Query> disjunctQueries = new ArrayList<>(); disjunctQueries.add(q1); disjunctQueries.add(q2); DisjunctionMaxQuery disjunctionMaxQuery = new DisjunctionMaxQuery(disjunctQueries, 0.0f); Set<String> extractedFieldNames = new HashSet<>(); disjunctionQueryExtracotr.extractSubQueriesFields(disjunctionMaxQuery, DEFAULT_EXTRACTORS, extractedFieldNames); assertEquals(2, extractedFieldNames.size()); assertTrue(extractedFieldNames.contains("field1")); assertTrue(extractedFieldNames.contains("field2")); }
protected boolean matchDisjunctionMaxQuery(DisjunctionMaxQuery dmq) { if (tieBreaker != dmq.getTieBreakerMultiplier()) { return false; } List<Query> dmqDisjuncts = dmq.getDisjuncts(); if (dmqDisjuncts == null || dmqDisjuncts.size() != disjuncts.length) { return false; } for (TypeSafeMatcher<? extends Query> disjunct : disjuncts) { boolean found = false; for (Query q : dmqDisjuncts) { found = disjunct.matches(q); if (found) { break; } } if (!found) { return false; } } return true; }
/** Creates a multifield query */ // TODO: investigate more general approach by default, e.g. DisjunctionMaxQuery? protected Query getMultiFieldQuery(List<Query> queries) throws ParseException { if (queries.isEmpty()) { return null; // all clause words were filtered away by the analyzer. } if (dismax) { return new DisjunctionMaxQuery(queries, dismaxTie); } else { //mdavis - don't use super method because of min match BooleanQuery.Builder query = new BooleanQuery.Builder(); for (Query sub : queries) { query.add(sub, BooleanClause.Occur.SHOULD); } return query.build(); } }
public void testExtractQueryMetadata_matchNoDocsQuery() { Result result = analyze(new MatchNoDocsQuery("sometimes there is no reason at all")); assertThat(result.verified, is(true)); assertEquals(0, result.terms.size()); BooleanQuery.Builder bq = new BooleanQuery.Builder(); bq.add(new TermQuery(new Term("field", "value")), BooleanClause.Occur.MUST); bq.add(new MatchNoDocsQuery("sometimes there is no reason at all"), BooleanClause.Occur.MUST); result = analyze(bq.build()); assertThat(result.verified, is(false)); assertEquals(0, result.terms.size()); bq = new BooleanQuery.Builder(); bq.add(new TermQuery(new Term("field", "value")), BooleanClause.Occur.SHOULD); bq.add(new MatchNoDocsQuery("sometimes there is no reason at all"), BooleanClause.Occur.SHOULD); result = analyze(bq.build()); assertThat(result.verified, is(true)); assertTermsEqual(result.terms, new Term("field", "value")); DisjunctionMaxQuery disjunctionMaxQuery = new DisjunctionMaxQuery( Arrays.asList(new TermQuery(new Term("field", "value")), new MatchNoDocsQuery("sometimes there is no reason at all")), 1f ); result = analyze(disjunctionMaxQuery); assertThat(result.verified, is(true)); assertTermsEqual(result.terms, new Term("field", "value")); }
@Override protected Query doToQuery(QueryShardContext context) throws IOException { // return null if there are no queries at all Collection<Query> luceneQueries = toQueries(queries, context); if (luceneQueries.isEmpty()) { return Queries.newMatchNoDocsQuery("no clauses for dismax query."); } return new DisjunctionMaxQuery(luceneQueries, tieBreaker); }
@Override protected void doAssertLuceneQuery(QueryStringQueryBuilder queryBuilder, Query query, SearchContext context) throws IOException { if ("".equals(queryBuilder.queryString())) { assertThat(query, instanceOf(MatchNoDocsQuery.class)); } else { assertThat(query, either(instanceOf(TermQuery.class)).or(instanceOf(AllTermQuery.class)) .or(instanceOf(BooleanQuery.class)).or(instanceOf(DisjunctionMaxQuery.class)) .or(instanceOf(PhraseQuery.class))); } }
public void testToQueryMultipleFieldsDisMaxQuery() throws Exception { assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0); Query query = queryStringQuery("test").field(STRING_FIELD_NAME).field(STRING_FIELD_NAME_2) .useDisMax(true) .toQuery(createShardContext()); assertThat(query, instanceOf(DisjunctionMaxQuery.class)); DisjunctionMaxQuery disMaxQuery = (DisjunctionMaxQuery) query; List<Query> disjuncts = disMaxQuery.getDisjuncts(); assertThat(((TermQuery) disjuncts.get(0)).getTerm(), equalTo(new Term(STRING_FIELD_NAME, "test"))); assertThat(((TermQuery) disjuncts.get(1)).getTerm(), equalTo(new Term(STRING_FIELD_NAME_2, "test"))); }
public void testToQueryDisMaxQuery() throws Exception { assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0); Query query = queryStringQuery("test").field(STRING_FIELD_NAME, 2.2f) .field(STRING_FIELD_NAME_2) .useDisMax(true) .toQuery(createShardContext()); assertThat(query, instanceOf(DisjunctionMaxQuery.class)); DisjunctionMaxQuery disMaxQuery = (DisjunctionMaxQuery) query; List<Query> disjuncts = disMaxQuery.getDisjuncts(); assertTermOrBoostQuery(disjuncts.get(0), STRING_FIELD_NAME, "test", 2.2f); assertTermOrBoostQuery(disjuncts.get(1), STRING_FIELD_NAME_2, "test", 1.0f); }
@Override protected void doAssertLuceneQuery(DisMaxQueryBuilder queryBuilder, Query query, SearchContext context) throws IOException { Collection<Query> queries = AbstractQueryBuilder.toQueries(queryBuilder.innerQueries(), context.getQueryShardContext()); assertThat(query, instanceOf(DisjunctionMaxQuery.class)); DisjunctionMaxQuery disjunctionMaxQuery = (DisjunctionMaxQuery) query; assertThat(disjunctionMaxQuery.getTieBreakerMultiplier(), equalTo(queryBuilder.tieBreaker())); assertThat(disjunctionMaxQuery.getDisjuncts().size(), equalTo(queries.size())); Iterator<Query> queryIterator = queries.iterator(); for (int i = 0; i < disjunctionMaxQuery.getDisjuncts().size(); i++) { assertThat(disjunctionMaxQuery.getDisjuncts().get(i), equalTo(queryIterator.next())); } }
public void testToQueryInnerPrefixQuery() throws Exception { assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0); String queryAsString = "{\n" + " \"dis_max\":{\n" + " \"queries\":[\n" + " {\n" + " \"prefix\":{\n" + " \"" + STRING_FIELD_NAME + "\":{\n" + " \"value\":\"sh\",\n" + " \"boost\":1.2\n" + " }\n" + " }\n" + " }\n" + " ]\n" + " }\n" + "}"; Query query = parseQuery(queryAsString).toQuery(createShardContext()); assertThat(query, instanceOf(DisjunctionMaxQuery.class)); DisjunctionMaxQuery disjunctionMaxQuery = (DisjunctionMaxQuery) query; List<Query> disjuncts = disjunctionMaxQuery.getDisjuncts(); assertThat(disjuncts.size(), equalTo(1)); assertThat(disjuncts.get(0), instanceOf(BoostQuery.class)); BoostQuery boostQuery = (BoostQuery) disjuncts.get(0); assertThat((double) boostQuery.getBoost(), closeTo(1.2, 0.00001)); assertThat(boostQuery.getQuery(), instanceOf(PrefixQuery.class)); PrefixQuery firstQ = (PrefixQuery) boostQuery.getQuery(); // since age is automatically registered in data, we encode it as numeric assertThat(firstQ.getPrefix(), equalTo(new Term(STRING_FIELD_NAME, "sh"))); }
@Override protected void doAssertLuceneQuery(MultiMatchQueryBuilder queryBuilder, Query query, SearchContext context) throws IOException { // we rely on integration tests for deeper checks here assertThat(query, either(instanceOf(BoostQuery.class)).or(instanceOf(TermQuery.class)).or(instanceOf(AllTermQuery.class)) .or(instanceOf(BooleanQuery.class)).or(instanceOf(DisjunctionMaxQuery.class)) .or(instanceOf(FuzzyQuery.class)).or(instanceOf(MultiPhrasePrefixQuery.class)) .or(instanceOf(MatchAllDocsQuery.class)).or(instanceOf(ExtendedCommonTermsQuery.class)) .or(instanceOf(MatchNoDocsQuery.class)).or(instanceOf(PhraseQuery.class)) .or(instanceOf(LegacyNumericRangeQuery.class)) .or(instanceOf(PointRangeQuery.class)).or(instanceOf(IndexOrDocValuesQuery.class))); }
public void testToQueryMultipleFieldsDisMaxQuery() throws Exception { assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0); Query query = multiMatchQuery("test").field(STRING_FIELD_NAME).field(STRING_FIELD_NAME_2).useDisMax(true).toQuery(createShardContext()); assertThat(query, instanceOf(DisjunctionMaxQuery.class)); DisjunctionMaxQuery disMaxQuery = (DisjunctionMaxQuery) query; List<Query> disjuncts = disMaxQuery.getDisjuncts(); assertThat(disjuncts.get(0), instanceOf(TermQuery.class)); assertThat(((TermQuery) disjuncts.get(0)).getTerm(), equalTo(new Term(STRING_FIELD_NAME, "test"))); assertThat(disjuncts.get(1), instanceOf(TermQuery.class)); assertThat(((TermQuery) disjuncts.get(1)).getTerm(), equalTo(new Term(STRING_FIELD_NAME_2, "test"))); }
protected Query dmq( float tieBreakerMultiplier, Query... queries ){ DisjunctionMaxQuery query = new DisjunctionMaxQuery( tieBreakerMultiplier ); for( Query q : queries ){ query.add( q ); } return query; }
public void testDisjunctionMaxQueryXML() throws ParserException, IOException { Query q = parse("DisjunctionMaxQuery.xml"); assertTrue(q instanceof DisjunctionMaxQuery); DisjunctionMaxQuery d = (DisjunctionMaxQuery)q; assertEquals(0.0f, d.getTieBreakerMultiplier(), 0.0001f); assertEquals(2, d.getDisjuncts().size()); DisjunctionMaxQuery ndq = (DisjunctionMaxQuery) d.getDisjuncts().get(1); assertEquals(1.2f, ndq.getTieBreakerMultiplier(), 0.0001f); assertEquals(1, ndq.getDisjuncts().size()); }
/** * Parses the query exactly like the Lucene parser does, but * delegates all SHOULD clauses to DisjunctionMaxQuery with * meaning only the clause with the max score will contribute * to the overall score, unless the tie parameter is specified. * <br/> * The max() is only calculated from the SHOULD clauses. * Any MUST clauses will be passed through as separate * BooleanClauses and thus always contribute to the score. * @return the resulting Query * @throws org.apache.solr.search.SyntaxError if parsing fails */ @Override public Query parse() throws SyntaxError { Query q = super.parse(); if (!(q instanceof BooleanQuery)) { return q; } BooleanQuery obq = (BooleanQuery)q; Collection<Query> should = new ArrayList<>(); Collection<BooleanClause> prohibOrReq = new ArrayList<>(); BooleanQuery newq = new BooleanQuery(); for (BooleanClause clause : obq.getClauses()) { if(clause.isProhibited() || clause.isRequired()) { prohibOrReq.add(clause); } else { BooleanQuery bq = new BooleanQuery(); bq.add(clause); should.add(bq); } } if (should.size() > 0) { DisjunctionMaxQuery dmq = new DisjunctionMaxQuery(should, tie); newq.add(dmq, BooleanClause.Occur.SHOULD); } for(BooleanClause c : prohibOrReq) { newq.add(c); } newq.setBoost(obq.getBoost()); return newq; }
/** * Delegates to the super class unless the field has been specified * as an alias -- in which case we recurse on each of * the aliased fields, and the results are composed into a * DisjunctionMaxQuery. (so yes: aliases which point at other * aliases should work) */ @Override protected Query getFieldQuery(String field, String queryText, boolean quoted) throws SyntaxError { if (aliases.containsKey(field)) { Alias a = aliases.get(field); DisjunctionMaxQuery q = new DisjunctionMaxQuery(a.tie); /* we might not get any valid queries from delegation, * in which case we should return null */ boolean ok = false; for (String f : a.fields.keySet()) { Query sub = getFieldQuery(f,queryText,quoted); if (null != sub) { if (null != a.fields.get(f)) { sub.setBoost(a.fields.get(f)); } q.add(sub); ok = true; } } return ok ? q : null; } else { try { return super.getFieldQuery(field, queryText, quoted); } catch (Exception e) { return null; } } }
private boolean containsClause(DisjunctionMaxQuery query, String field, String value, int boost, boolean fuzzy) { for(Query disjunct:query.getDisjuncts()) { if(containsClause(disjunct, field, value, boost, fuzzy)) { return true; } } return false; }
public String toString(Query query, String field) { StringBuilder buffer = new StringBuilder(); if (query instanceof TermQuery) { buffer.append(toString((TermQuery) query, field)); } else if (query instanceof BooleanQuery) { buffer.append(toString((BooleanQuery) query, field)); } else if (query instanceof WildcardQuery) { buffer.append(toString((WildcardQuery) query, field)); } else if (query instanceof PhraseQuery) { buffer.append(toString((PhraseQuery) query, field)); } else if (query instanceof PrefixQuery) { buffer.append(toString((PrefixQuery) query, field)); } else if (query instanceof MultiPhraseQuery) { buffer.append(toString((MultiPhraseQuery) query, field)); } else if (query instanceof FuzzyQuery) { buffer.append(toString((FuzzyQuery) query, field)); } else if (query instanceof RegexpQuery) { buffer.append(toString((RegexpQuery) query, field)); } else if (query instanceof TermRangeQuery) { buffer.append(toString((TermRangeQuery) query, field)); } else if (query instanceof ConstantScoreQuery) { buffer.append(toString((ConstantScoreQuery) query, field)); } else if (query instanceof DisjunctionMaxQuery) { buffer.append(toString((DisjunctionMaxQuery) query, field)); } else if (query instanceof MatchAllDocsQuery) { buffer.append(toString((MatchAllDocsQuery) query, field)); } else if (query instanceof SynonymQuery) { buffer.append(toString((SynonymQuery) query, field)); } else { buffer.append(query.toString(field)); } return buffer.toString(); }
protected String toString(DisjunctionMaxQuery disjunctionMaxQuery, String field) { StringBuilder buffer = new StringBuilder(); List<Query> disjuncts = disjunctionMaxQuery.getDisjuncts(); float tieBreakerMultiplier = disjunctionMaxQuery.getTieBreakerMultiplier(); buffer.append("("); for (int i = 0; i < disjuncts.size(); i++) { Query subquery = disjuncts.get(i); if (subquery instanceof BooleanQuery) { // wrap sub-bools in parens buffer.append("("); buffer.append(toString(subquery, field)); buffer.append(")"); } else buffer.append(toString(subquery, field)); if (i != disjuncts.size() - 1) buffer.append(" | "); } buffer.append(")"); if (tieBreakerMultiplier != 0.0f) { buffer.append("~"); buffer.append(tieBreakerMultiplier); } return buffer.toString(); }
@Override public void extract(final DisjunctionMaxQuery q, final Iterable<QueryExtractor<? extends Query>> extractors, final List<Query> extractedQueries) throws UnsupportedOperationException { for (Query internalQuery : q) { extractQuery(internalQuery, extractors, extractedQueries); } }
@Override public void extractSubQueriesFields(final DisjunctionMaxQuery q, final Iterable<QueryExtractor<? extends Query>> extractors, final Set<String> extractedFields) throws UnsupportedOperationException { for (final Query internalQuery : q) { extractFields(internalQuery, extractors, extractedFields); } }