Solr:strange(? maybe not) behaviors of negative query

documents:

{"id":1,content:"test1"}
{"id":2,content:"test2"}
{"id":3,content:"test3"}

various patterns of query string and the parsed result

1.content:((NOT “test1”) AND (NOT “test2”))

==> parsed string = +(-content:test1) +(-content:test2)

==> returns nothing

2.content:(NOT “test1” AND NOT “test2”)

==> parsed string = -content:test1 -content:test2

==> returns #3

3.content:((* NOT “test1”) AND (* NOT “test2”))

==> parsed string = +(content:* -content:test1) +(content:* -content:test2)

==> returns #3

The Point

NOT must negate results of a query, not the entire dataset.

Why the first two queries give different result?

Solr currently checks for a “pure negative” query and inserts `*:*` (which matches all documents) so that the latter format(that without parentheses) works correctly.

See the code snippet below from org.apache.solr.search.QueryUtils.java

/** Fixes a negative query by adding a MatchAllDocs query clause.
  * The query passed in *must* be a negative query.
  */
 public static Query fixNegativeQuery(Query q) {
   BooleanQuery newBq = (BooleanQuery)q.clone();
   newBq.add(new MatchAllDocsQuery(), BooleanClause.Occur.MUST);
   return newBq;
 }

So `NOT “test”` is transformed by solr into `(*:* NOT “test”)`

But Solr only checks only the top level query,so this means that a query like `(NOT “test1”)` is not changed since the pure negative query is not in the top level.
This is why the former format (that with parentheses) does not work as expected.

So,we can conclude generally that the proper way to `NOT` operator is the `(*:* NOT some_expression)`,instead of a single `NOT some_expression`.

References

Negation in solr query
using OR and NOT in solr query
OR/NOT query syntax
Negative operator(NOT,- , !) in solr query string doesn’t work with parentheses