Lucene: RangeQuery vs. RangeFilter
Eine gängie Suche bei Dokumenten z.B. ist die Suche in bestimmten Zeiträumen oder auch bei Produkten die Filterung nach Preisen. Lucene bietet dafür zwei Möglichkeiten an, welche sich in der Ausführungsart und im Ausführungszeitpunkt unterscheiden. RangeQuery ist eine Einschränkung für eine Abfrage um einen Wert entsprechend zu begrenzen. Wenn der QueryParser verwendet wird, so lautet die Syntax:
field:[2002 TO 5000]
. Statt den eckigen Klammern können auch geschweifte Klammern verwendet werden um die Werte 2002 und 5000 nicht mit in die Suche einzubeziehen. RangeQuery arbeitet intern als Booleanquery. Beim erstellen sucht es aus dem Index alle Terme heraus, die in die Grenzen passen, und erzeugt daraus ein entsprechendes BooleanQuery. In unserem Fall wohl 2002 OR 2003 OR 2004 OR …. OR 5000. Das Problem hierbei ist, dass schnell die maximale Grenze von BooleanQuery erreicht wird. Diese liegt standardmäßig bei 1024 und kann mit BooleanQuery.setMaxClauseCount() verändert werden. Bis ins unendliche sollte dies jedoch aus Speicher und Ausführungsgründen nicht getrieben werden. Es ist hier also schon absehbar, dass RangeQuery zwar schön und schnell einsetzbar ist und auch die Suche entsprechend schnell ist, jedoch nur bei eine begrenzten Anzahl an Termen einsetzbar.
Für unseren Fall, sofern zwischen 2002 und 5000 (fast) jedes Element vorhanden ist, bietet sich daher der RangeFilter an. Dieser baut ein Bitset über die Dokumente vor der Suche auf, welches die Zugehörigkeit der Dokumente zur Range entsprechend angibt. Dadurch ist dies natürlich etwas langsamer und entsprechend Speicherintensiver bei sehr großen Indizies. Es bietet sich jedoch vor allem bei Preissuchen, etc. an. Bei der Indizierung von Double-Werten z.B. sollte man jedoch darauf achten diese mit Vornullen zu indizieren, da sonst bei der Sortierung und bei RangeQuery / RangeFilter die Reihenfolge unerwartete Ergebnisse liefert.
Ohne Vornullen:
0.12 1.10 1.32 10.123 2.12 5.60
Mit Vornullen:
00000.12 00001.10 00001.32 00002.12 00005.60 00010.123