Запрос Lucene BlockJoin для соответствия, когда все термины появляются в родительских или дочерних документах - PullRequest
2 голосов
/ 04 июня 2019

Я заполнил индекс родительскими и дочерними документами, используя «Блоки». то есть документы добавляются с использованием метода IndexWriter.addAll (), причем последний документ является родительским документом.

На данный момент мне удалось найти только «блоки», в результате чего любые термины в запросе отображаются либо в родительском, либо в дочернем. Это дает мне искаженные результаты. например Я получаю лучшие результаты, когда один из терминов многократно встречается в блоке, но другие термины не отображаются вообще.

Я хочу найти «Блоки», в результате чего все термины в запросе должны появляться либо в родительском, либо в дочернем.

Но я не уверен, как построить запрос.

Мой текущий код запроса выглядит следующим образом:

Analyzer analyzer = new EnglishAnalyzer();
//Note, both parent and child docs have a 'textContent' field
QueryParser queryParser = new QueryParser("textContent", analyzer);
Directory index = FSDirectory.open(Paths.get("${indexParentDir}/${name}.lucene"));
BitSetProducer parentsFilter = new QueryBitSetProducer(new TermQuery(new Term("child", "N")));

Query textQuery = queryParser.parse("foo bar");

//Construct child query
BooleanQuery.Builder childQueryBuilder = new BooleanQuery.Builder();
childQueryBuilder.add(new BooleanClause(textQuery, BooleanClause.Occur.MUST));
childQueryBuilder.add(new BooleanClause(new TermQuery(new Term("child", "Y")), BooleanClause.Occur.MUST));
Query childQuery = new ToParentBlockJoinQuery(childQueryBuilder.build(), parentsFilter, ScoreMode.Avg);

//Construct parent query
BooleanQuery.Builder parentQueryBuilder = new BooleanQuery.Builder();
parentQueryBuilder.add(new BooleanClause(textQuery, BooleanClause.Occur.MUST));
parentQueryBuilder.add(new BooleanClause(new TermQuery(new Term("child", "N")), BooleanClause.Occur.MUST));

//Construct join of child and parent query
BooleanQuery.Builder childAndParentQueryBuilder = new BooleanQuery.Builder();
childAndParentQueryBuilder.add(new BooleanClause(childQuery, BooleanClause.Occur.SHOULD));
childAndParentQueryBuilder.add(new BooleanClause(parentQueryBuilder.build(), BooleanClause.Occur.SHOULD));
Query childAndParentQuery = childAndParentQueryBuilder.build();

//Run the query
DirectoryReader reader = DirectoryReader.open(index);
CheckJoinIndex.check(reader, parentsFilter);
IndexSearcher searcher = new IndexSearcher(reader);
searcher.search(childAndParentQuery, 10);

Приведенный выше код вернет лучшие результаты, в результате чего один из терминов встречается много раз. например Если 'foo' появляется 100 раз в родительских или дочерних документах. Но «бар» вообще не появляется.

Я хотел бы вернуть только результаты, при которых все термины (например, 'foo' и 'bar') появляются либо в родительском, либо в одном из его дочерних элементов.

Один из вариантов - создать поле в родительских документах, которое представляет собой объединение всех полей textContent в родительских и дочерних документах и ​​выполнять поиск только в новом агрегированном поле. Но эти показатели уже довольно велики. (например, 50 ГБ). И я все еще должен хранить textContent отдельно для родительских и дочерних элементов для отображения, поэтому создание агрегированного поля почти удвоит размер индекса.

Буду признателен за любую помощь.

1 Ответ

0 голосов
/ 14 июня 2019

Я решил эту проблему, используя DisjunctionMaxQuery вместо BooleanQuery для объединения родительских и дочерних запросов.

Из документации:

... Мы хотим, чтобы основной счет был тот, который связан с наибольшим усилением, а не сумма полевых результатов (как даст BooleanQuery).Если запрос «слон-альбинос», это гарантирует, что «альбинос», соответствующий одному полю, и «слон», соответствующий другому, получат более высокий балл, чем «альбинос», соответствующий обоим полям ...

Обновленный код:

Analyzer analyzer = new EnglishAnalyzer();

//Note, both parent and child docs have a 'textContent' field
QueryParser queryParser = new QueryParser("textContent", analyzer);
Directory index = FSDirectory.open(Paths.get("${indexParentDir}/${name}.lucene"));
BitSetProducer parentsFilter = new QueryBitSetProducer(new TermQuery(new Term("child", "N")));

Query textQuery = queryParser.parse("foo bar");

//Construct child query
BooleanQuery.Builder childQueryBuilder = new BooleanQuery.Builder();
childQueryBuilder.add(new BooleanClause(textQuery, BooleanClause.Occur.MUST));
childQueryBuilder.add(new BooleanClause(new TermQuery(new Term("child", "Y")), BooleanClause.Occur.MUST));
Query childQuery = new ToParentBlockJoinQuery(childQueryBuilder.build(), parentsFilter, ScoreMode.Avg);

//Construct parent query
BooleanQuery.Builder parentQueryBuilder = new BooleanQuery.Builder();
parentQueryBuilder.add(new BooleanClause(textQuery, BooleanClause.Occur.MUST));
parentQueryBuilder.add(new BooleanClause(new TermQuery(new Term("child", "N")), BooleanClause.Occur.MUST));
Query parentQuery = parentQueryBuilder.build();

//Construct join of child and parent query
Query childAndParentQuery = new DisjunctionMaxQuery(Arrays.asList(childQuery, parentQuery), 0.5f);

//Run the query
DirectoryReader reader = DirectoryReader.open(index);
CheckJoinIndex.check(reader, parentsFilter);
IndexSearcher searcher = new IndexSearcher(reader);
searcher.search(childAndParentQuery, 10);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...