/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.solr.search; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.Query; import org.apache.lucene.index.Term; import org.apache.solr.util.AbstractSolrTestCase; import org.junit.BeforeClass; import java.util.Collection; /** * */ public class TestQueryUtils extends AbstractSolrTestCase { @BeforeClass public static void beforeClass() throws Exception { initCore("solrconfig.xml", "schema.xml"); } @Override public void setUp() throws Exception { super.setUp(); } @Override public void tearDown() throws Exception { super.tearDown(); } public void positive(Query q) { assertFalse(QueryUtils.isNegative(q)); assertTrue(QueryUtils.getAbs(q)==q); Collection<BooleanClause> clauses = (q instanceof BooleanQuery) ? ((BooleanQuery)q).clauses() : null; if (clauses != null) { if (clauses.size() != 0) { assertTrue(QueryUtils.makeQueryable(q)==q); } } else { assertTrue(QueryUtils.makeQueryable(q)==q); } } public void negative(Query q) { assertTrue(QueryUtils.isNegative(q)); Query abs = QueryUtils.getAbs(q); assertTrue(q != abs); Query neg2 = QueryUtils.fixNegativeQuery(q); assertFalse(abs.equals(q)); assertFalse(neg2.equals(q)); } public void testNegativeQueries() { TermQuery tq = new TermQuery(new Term("hi","there")); TermQuery tq2 = new TermQuery(new Term("wow","dude")); BooleanQuery.Builder bq = new BooleanQuery.Builder(); positive(tq); // positive(bq); bq.add(tq, BooleanClause.Occur.SHOULD); positive(bq.build()); bq.add(tq2, BooleanClause.Occur.MUST_NOT); positive(bq.build()); bq = new BooleanQuery.Builder(); bq.add(tq,BooleanClause.Occur.MUST_NOT); negative(bq.build()); bq.add(tq2,BooleanClause.Occur.MUST_NOT); negative(bq.build()); String f = "name"; // name is whitespace tokenized assertU(adoc("id", "1", f, "A")); assertU(adoc("id", "2", f, "B")); assertU(adoc("id", "3", f, "C")); assertU(adoc("id", "4", f, "C")); assertU(adoc("id", "5", f, "D")); assertU(adoc("id", "6", f, "E")); assertU(adoc("id", "7", f, "E")); assertU(adoc("id", "8", f, "E W")); assertU(adoc("id", "9", f, "F W")); assertU(adoc("id", "10", f, "G W")); assertU(adoc("id", "11", f, "G X ")); assertU(adoc("id", "12", f, "G X Y")); assertU(adoc("id", "13", f, "G X Y Z")); assertU(adoc("id", "14", f, "G Y Z")); assertU(adoc("id", "15", f, "G Z")); assertU(adoc("id", "16", f, "G")); assertU(commit()); assertQ("test negative base q matching nothing", req("-qlkciyopsbgzyvkylsjhchghjrdf") ,"//result[@numFound='16']" ); assertQ("test negative base q matching something", req("-name:E") ,"//result[@numFound='13']" ); assertQ("test negative base q with two terms", req("-name:G -name:W") ,"//result[@numFound='7']" ); assertQ("test negative base q with three terms", req("-name:G -name:W -name:E") ,"//result[@numFound='5']" ); assertQ("test negative boolean query", req("-(name:G OR name:W)") ,"//result[@numFound='7']" ); assertQ("test non negative q", req("-name:G -name:W -name:E id:[* TO *]") ,"//result[@numFound='5']" ); assertQ("test non negative q", req("-name:G -name:W -name:E +id:[* TO *]") ,"//result[@numFound='5']" ); // now for the filters... assertQ("test negative base q matching nothing, with filters", req("q","-qlkciyopsbgzyvkylsjhchghjrdf" ,"fq","name:A" ) ,"//result[@numFound='1']" ); assertQ("test negative filters", req("q","name:A" ,"fq","-name:A" ) ,"//result[@numFound='0']" ); assertQ("test negative filters", req("q","name:A" ,"fq","-name:A" ) ,"//result[@numFound='0']" ); assertQ("test negative filters", req("q","-name:E" ,"fq","name:E" ) ,"//result[@numFound='0']" ); assertQ("test negative filters", req("q","-name:E" ,"fq","name:W" ) ,"//result[@numFound='2']" ); assertQ("test negative filters", req("q","-name:E" ,"fq","name:W" ) ,"//result[@numFound='2']" ); assertQ("one pos filter, one neg", req("q","-name:E" ,"fq","name:W" ,"fq","-name:G" ) ,"//result[@numFound='1']" ); assertQ("two neg filters", req("q","-name:E" ,"fq","-name:W" ,"fq","-name:G" ) ,"//result[@numFound='5']" // ABCCD ); assertQ("three neg filters", req("q","-name:E" ,"fq","-name:W" ,"fq","-name:G" ,"fq","-name:C" ) ,"//result[@numFound='3']" // ABD ); assertQ("compound neg filters", req("q","-name:E" ,"fq","-name:W -name:G" ,"fq","-name:C" ) ,"//result[@numFound='3']" // ABD ); assertQ("compound neg filters", req("q","-name:E" ,"fq","-name:W -name:G -name:C" ) ,"//result[@numFound='3']" // ABD ); assertQ("compound neg filters", req("q","-name:E" ,"fq","-(name:W name:G name:C)" ) ,"//result[@numFound='3']" // ABD ); assertQ("three neg filters + pos", req("q","-name:E" ,"fq","-name:W" ,"fq","-name:G" ,"fq","-name:C" ,"fq","name:G" ) ,"//result[@numFound='0']" ); assertQ("three neg filters + pos", req("q","-name:E" ,"fq","-name:W" ,"fq","-name:G" ,"fq","-name:C" ,"fq","+id:1" ) ,"//result[@numFound='1']" // A ); assertQ("three neg filters + pos", req("q","-name:E" ,"fq","-name:W" ,"fq","-name:G" ,"fq","-name:C" ,"fq","id:[* TO *]" ) ,"//result[@numFound='3']" // ABD ); // QueryParser turns term queries on stopwords into a BooleanQuery with // zero clauses. assertQ("neg base query on stopword", req("q","-text:stopworda") ,"//result[@numFound='16']" // ABD ); assertQ("negative filter on stopword", req("q","id:[* TO *]" ,"fq","-text:stopworda" ) ,"//result[@numFound='16']" // ABD ); assertQ("two negative filters on stopword", req("q","id:[* TO *]" ,"fq","-text:stopworda" ,"fq","-text:stopworda" ) ,"//result[@numFound='16']" // ABD ); assertQ("compound negative filters with stopword", req("q","id:[* TO *]" ,"fq","-text:stopworda -id:1" ) ,"//result[@numFound='15']" // ABD ); } }