Я пытаюсь объединить фильтрацию дат и запросы к нескольким текстовым полям в Lucene.
Например, я хочу запросить заголовок и содержание документ и включать только те документы, которые обновили поле в определенном диапазоне дат.
Странное поведение, с которым я сталкиваюсь, заключается в том, что когда я добавляю фильтр даты, я получаю документы включены в результаты, которые соответствуют фильтру даты, но не соответствуют строке запроса.
Есть документы с оценкой совпадения буквально 0,0, которые возвращаются.
Я что-то упустил при построении запроса? Или это приемлемое поведение, и мне следует просто отфильтровать документы с оценкой 0,0 из результатов?
Ниже приведен пример кода с выводом:
Код
Использование кода Lucene 7.3.0 и примера кода Kotlin:
package lookup.lucene
import org.apache.lucene.analysis.standard.StandardAnalyzer
import org.apache.lucene.document.Document
import org.apache.lucene.document.Field
import org.apache.lucene.document.LongPoint
import org.apache.lucene.document.TextField
import org.apache.lucene.index.*
import org.apache.lucene.search.*
import org.apache.lucene.store.Directory
import org.apache.lucene.store.RAMDirectory
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*
object DateFilterTroubleshootingSandbox {
private val indexDirectory: Directory = RAMDirectory()
private val analyzer = StandardAnalyzer()
val dateFormatter = SimpleDateFormat("yyyy-MM-dd", Locale.US)
@Throws(IOException::class)
@JvmStatic
fun main(args: Array) {
setupIndex()
// "ergonomic keyboard"
performSearchWithDateFilter("ergonomic")
}
@Throws(IOException::class)
private fun setupIndex() {
val config = IndexWriterConfig(analyzer)
val writer = IndexWriter(indexDirectory, config)
addDoc(
writer,
"ergonomic keyboard Review (title and content match)",
"Review of the latest ergonomic keyboard",
dateFormatter.parse("2024-04-02").time
)
addDoc(
writer,
"Cycling Updates (completely unrelated)",
"Best bicycles of 2024",
dateFormatter.parse("2024-04-10").time
)
addDoc(
writer,
"Office Comfort (on word in content matches)",
"Review of ergonomic chairs",
dateFormatter.parse("2024-04-15").time
)
writer.close()
}
@Throws(IOException::class)
private fun addDoc(
writer: IndexWriter,
title: String,
content: String,
updatedMillis: Long,
) {
val doc = Document()
doc.add(TextField("title", title, Field.Store.YES))
doc.add(TextField("content", content, Field.Store.YES))
doc.add(LongPoint("updatedMillis", updatedMillis))
writer.addDocument(doc)
}
@Throws(IOException::class)
private fun performSearchWithDateFilter(queryString: String) {
println("performSearchWithDateFilter: $queryString")
val reader: IndexReader = DirectoryReader.open(indexDirectory)
val searcher = IndexSearcher(reader)
val query = buildQuery(queryString, "2024-04-09", "2024-04-22")
val docs = searcher.search(query, 10)
printDocs(searcher, docs)
reader.close()
}
private fun buildQuery(queryString: String, fromDate: String, toDate: String): Query {
val booleanQuery = BooleanQuery.Builder()
arrayOf("title", "content")
.forEach { field ->
booleanQuery.add(
BoostQuery(TermQuery(Term(field, queryString)), 1.1f), BooleanClause.Occur.SHOULD
)
}
val fromMillis = dateFormatter.parse(fromDate).time
val toMillis = dateFormatter.parse(toDate).time
val dateRangeQuery = LongPoint.newRangeQuery("updatedMillis", fromMillis, toMillis)
booleanQuery.add(dateRangeQuery, BooleanClause.Occur.FILTER)
return booleanQuery.build()
}
private fun printDocs(searcher: IndexSearcher, docs: TopDocs) {
docs.scoreDocs.forEach { scoreDoc ->
val docId = scoreDoc.doc
val doc = searcher.doc(docId)
val title = doc.get("title")
val content = doc.get("content")
println("Doc ID: $docId, Score: ${scoreDoc.score}, Title='$title', Content='$content'")
}
}
}
Вывод
performSearchWithDateFilter: ergonomic
Doc ID: 2, Score: 0.5390563, Title='Office Comfort (on word in content matches)', Content='Review of ergonomic chairs'
Doc ID: 1, Score: 0.0, Title='Cycling Updates (completely unrelated)', Content='Best bicycles of 2024'
Подробнее здесь: https://stackoverflow.com/questions/784 ... alues-caus