Объединение запросов с числовым диапазоном с запросом терминов в Lucene

Я хотел бы объединить запрос числового диапазона с термином query в Lucene. Например, я хочу найти документы, которые я индексировал, которые содержат от 10 до 20 страниц и имеют заголовок "Hello World".

Кажется, что невозможно использовать QueryParser для генерации этого запроса для меня; запрос диапазона, который генерирует QueryParser, представляется текстовым.

Мне определенно понравился бы пример того, как объединить запрос числового диапазона с термином query. Я также был бы открыт, беря альтернативу поиску моего индекса.

Спасибо

Ответ 1

Хорошо, похоже, я сам это понял. Вы можете использовать Query.combine() для OR запросов вместе. Я привел пример ниже.

String termQueryString = "title:\"hello world\"";
Query termQuery = parser.parse(termQueryString);

Query pageQueryRange = NumericRangeQuery.newIntRange("page_count", 10, 20, true, true);

Query query = termQuery.combine(new Query[]{termQuery, pageQueryRange});

Ответ 2

Вы также можете создать собственный QueryParser, переопределяющий метод protected Query getRangeQuery(...), который должен возвращать экземпляр NumericRangeQuery, когда встречается поле "page_count".

Так же...

public class CustomQueryParser extends QueryParser {

    public CustomQueryParser(Version matchVersion, String f, Analyzer a) {
        super(matchVersion, f, a);
    }

    @Override
    protected Query getRangeQuery(final String field, final String part1, final String part2, final boolean inclusive) throws ParseException {

        if ("page_count".equals(field)) {
            return NumericRangeQuery.newIntRange(field, Integer.parseInt(part1), Integer.parseInt(part2), inclusive, inclusive);
        }

        // return default
        return super.getRangeQuery(field, part1, part2, inclusive);    
    }
}

Затем используйте CustomQueryParser при анализе текстовых запросов.

Так же...

...
final QueryParser parser = new CustomQueryParser(Version.LUCENE_35, "some_default_field", new StandardAnalyzer(Version.LUCENE_35));
final Query q = parser.parse("title:\"hello world\" AND page_count:[10 TO 20]");
...

Все это, конечно, предполагает, что NumericField(...).setIntValue(...) использовался, когда были добавлены значения

Ответ 3

Вы можете использовать BooleanQuery:

var combinedQuery = new BooleanQuery();
combinedQuery.Add(new TermQuery(new Term("title","hello world")),Occur.MUST);
combinedQuery.Add(NumericRangeQuery.newIntRange("page_count", 10, 20, true, true),Occur.MUST);

Ответ 4

RangeQuery amountQuery = new RangeQuery(lowerTerm, upperTerm, true);

Lucene обрабатывает числа как слова, поэтому числа упорядочены по алфавиту.

1
12
123
1234
etc.

При этом вы все равно можете использовать запрос диапазона, вам просто нужно быть более умным.

Чтобы правильно запросить числовые значения, вам нужно заполнить целые числа одинаковой длиной (независимо от вашего максимального поддерживаемого значения)

0001
0012
0123
1234

Очевидно, что это не работает для отрицательных чисел (поскольку -2 < -1), и, надеюсь, вам не придется иметь дело с ними. Вот полезная статья для негативов, если вы столкнулись с ними: http://wiki.apache.org/lucene-java/SearchNumericalFields