Skip to content

Commit 3d3b60a

Browse files
committed
fix: lucene query some cases not negates closes#71
1 parent 76d4bc6 commit 3d3b60a

3 files changed

Lines changed: 53 additions & 28 deletions

File tree

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ licenses += ("Apache-2.0", url("https://www.apache.org/licenses/LICENSE-2.0.html
4343
//crossScalaVersions := Seq("2.13.16")
4444
crossScalaVersions := Seq("3.6.0", "2.13.16")
4545

46-
scalaVersion := crossScalaVersions.value.last
46+
scalaVersion := crossScalaVersions.value.head
4747

4848
scalacOptions += "-deprecation"
4949

src/main/scala/dev/mongocamp/driver/mongodb/lucene/LuceneQueryConverter.scala

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import com.typesafe.scalalogging.LazyLogging
44
import dev.mongocamp.driver.mongodb._
55
import dev.mongocamp.driver.mongodb.exception.NotSupportedException
66
import org.apache.lucene.queryparser.classic.QueryParser
7-
import org.apache.lucene.search._
87
import org.apache.lucene.search.BooleanClause.Occur
8+
import org.apache.lucene.search._
99
import org.joda.time.DateTime
1010
import org.mongodb.scala.bson.conversions.Bson
1111

@@ -35,7 +35,7 @@ object LuceneQueryConverter extends LazyLogging {
3535
private def getMongoDbSearchMap(query: Query, negated: Boolean, searchWithValueAndString: Boolean): Map[String, Any] = {
3636
val searchMapResponse = mutable.Map[String, Any]()
3737
query match {
38-
case booleanQuery: BooleanQuery => appendBooleanQueryToSearchMap(searchMapResponse, booleanQuery, searchWithValueAndString)
38+
case booleanQuery: BooleanQuery => appendBooleanQueryToSearchMap(searchMapResponse, booleanQuery, searchWithValueAndString, negated)
3939
case termRangeQuery: TermRangeQuery => appendTermRangeQueryToSearchMap(negated, searchMapResponse, termRangeQuery, searchWithValueAndString)
4040
case termQuery: TermQuery => appendTermQueryToSearchMap(negated, searchMapResponse, termQuery, searchWithValueAndString)
4141
case query: PrefixQuery => appendPrefixQueryToSearchMap(negated, searchMapResponse, query)
@@ -53,14 +53,17 @@ object LuceneQueryConverter extends LazyLogging {
5353
private def appendBooleanQueryToSearchMap(
5454
searchMapResponse: mutable.Map[String, Any],
5555
booleanQuery: BooleanQuery,
56-
searchWithValueAndString: Boolean
56+
searchWithValueAndString: Boolean,
57+
negate: Boolean
5758
): Unit = {
5859
val subQueries = booleanQuery.clauses().asScala
5960
val listOfAnd = ArrayBuffer[Map[String, Any]]()
6061
val listOfOr = ArrayBuffer[Map[String, Any]]()
62+
val listOfNOr = ArrayBuffer[Map[String, Any]]()
6163
var nextTypeAnd = true
6264
subQueries.foreach(c => {
63-
val queryMap = getMongoDbSearchMap(c.query(), c.isProhibited, searchWithValueAndString)
65+
val negateSubquery = (c.occur() == Occur.MUST_NOT)
66+
val queryMap = getMongoDbSearchMap(c.query(), negateSubquery, searchWithValueAndString)
6467
var thisTypeAnd = true
6568

6669
if (c.occur == Occur.MUST) {
@@ -87,10 +90,18 @@ object LuceneQueryConverter extends LazyLogging {
8790
})
8891

8992
if (listOfAnd.nonEmpty) {
90-
searchMapResponse.put("$and", listOfAnd.toList)
93+
if (negate) {
94+
searchMapResponse.put("$nor", listOfAnd.toList)
95+
} else {
96+
searchMapResponse.put("$and", listOfAnd.toList)
97+
}
9198
}
9299
if (listOfOr.nonEmpty) {
93-
searchMapResponse.put("$or", listOfOr.toList)
100+
if (negate) {
101+
searchMapResponse.put("$nor", listOfOr.toList)
102+
} else {
103+
searchMapResponse.put("$or", listOfOr.toList)
104+
}
94105
}
95106
}
96107

@@ -186,15 +197,17 @@ object LuceneQueryConverter extends LazyLogging {
186197
}
187198

188199
private def appendPhraseQueryToSearchMap(negated: Boolean, searchMapResponse: mutable.Map[String, Any], query: PhraseQuery): Unit = {
189-
val listOfSearches = query.getTerms.map(term => {
190-
val convertedValue = checkAndConvertValue(term.text())
191-
if (convertedValue.isInstanceOf[String]) {
192-
Map(term.field() -> generateRegexQuery(s"(.*?)$convertedValue(.*?)", "i"))
193-
}
194-
else {
195-
Map(term.field() -> Map("$eq" -> convertedValue))
196-
}
197-
}).toList
200+
val listOfSearches = query.getTerms
201+
.map(term => {
202+
val convertedValue = checkAndConvertValue(term.text())
203+
if (convertedValue.isInstanceOf[String]) {
204+
Map(term.field() -> generateRegexQuery(s"(.*?)$convertedValue(.*?)", "i"))
205+
}
206+
else {
207+
Map(term.field() -> Map("$eq" -> convertedValue))
208+
}
209+
})
210+
.toList
198211
if (negated) {
199212
searchMapResponse.put("$nor", listOfSearches)
200213
}
@@ -228,18 +241,20 @@ object LuceneQueryConverter extends LazyLogging {
228241
val convertedValue: Option[Any] =
229242
(List() ++ checkOrReturn(() => s.toDouble) ++ checkOrReturn(() => s.toLong) ++ checkOrReturn(() => s.toBoolean)).headOption
230243
val response = convertedValue.getOrElse({
231-
val parsedOptions: List[Date] = Try(new DateTime(s).toDate).toOption.toList ++ datePatters.flatMap(pattern => {
232-
try {
233-
val formatter = new SimpleDateFormat(pattern)
234-
val r = Option(formatter.parse(s))
235-
logger.info(s"parsed date $s with pattern $pattern to $r")
236-
r
237-
}
238-
catch {
239-
case e: Exception =>
240-
None
241-
}
242-
}).distinct
244+
val parsedOptions: List[Date] = Try(new DateTime(s).toDate).toOption.toList ++ datePatters
245+
.flatMap(pattern => {
246+
try {
247+
val formatter = new SimpleDateFormat(pattern)
248+
val r = Option(formatter.parse(s))
249+
logger.info(s"parsed date $s with pattern $pattern to $r")
250+
r
251+
}
252+
catch {
253+
case e: Exception =>
254+
None
255+
}
256+
})
257+
.distinct
243258
parsedOptions.headOption.getOrElse(s)
244259
})
245260
response

src/test/scala/dev/mongocamp/driver/mongodb/lucene/LuceneSearchSuite.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package dev.mongocamp.driver.mongodb.lucene
33
import dev.mongocamp.driver.mongodb._
44
import dev.mongocamp.driver.mongodb.dao.BasePersonSuite
55
import dev.mongocamp.driver.mongodb.test.TestDatabase._
6+
import org.mongodb.scala.Document
67

78
import java.util.TimeZone
89

@@ -135,4 +136,13 @@ class LuceneSearchSuite extends BasePersonSuite {
135136
assertEquals(search.size, 199)
136137
}
137138

139+
test("negate query with values in braces") {
140+
val luceneQuery = LuceneQueryConverter.parse("NOT fieldName:('value1' OR 'value2' OR 'value2')", "ube")
141+
val document = LuceneQueryConverter.toDocument(luceneQuery)
142+
assertEquals("{\"$and\": [{\"$nor\": [{\"fieldName\": {\"$eq\": \"value1\"}}, {\"fieldName\": {\"$eq\": \"value2\"}}, {\"fieldName\": {\"$eq\": \"value2\"}}]}]}", document.asInstanceOf[Document].toJson())
143+
val luceneQuery2 = LuceneQueryConverter.parse("NOT fieldName:('value1' AND 'value2' AND 'value2')", "ube")
144+
val document2 = LuceneQueryConverter.toDocument(luceneQuery2)
145+
assertEquals("{\"$and\": [{\"$nor\": [{\"fieldName\": {\"$eq\": \"value1\"}}, {\"fieldName\": {\"$eq\": \"value2\"}}, {\"fieldName\": {\"$eq\": \"value2\"}}]}]}", document2.asInstanceOf[Document].toJson())
146+
}
147+
138148
}

0 commit comments

Comments
 (0)