Lucene: словосочетания в качестве поисковых терминов - PullRequest
7 голосов
/ 30 января 2012

Я пытаюсь создать доступный для поиска телефонный / местный бизнес-справочник, используя Apache Lucene.

У меня есть поля для названия улицы, названия компании, номера телефона и т. Д. Проблема, с которой я сталкиваюсь, заключается в том, что, когда я пытаюсь выполнить поиск по улице, где название улицы состоит из нескольких слов (например, «полумесяц»), нет результатов. возвращаются. Но если я попытаюсь выполнить поиск по одному слову, например, «полумесяц», я получу все нужные результаты.

Я индексирую данные следующим образом:

String LocationOfDirectory = "C:\\dir\\index";

StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_34);
Directory Index = new SimpleFSDirectory(LocationOfDirectory);

IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE.34, analyzer);
IndexWriter w = new IndexWriter(index, config);


Document doc = new Document();
doc.add(new Field("Street", "the crescent", Field.Store.YES, Field.Index.Analyzed);

w.add(doc);
w.close();

Мой поиск работает так:

int numberOfHits = 200;
String LocationOfDirectory = "C:\\dir\\index";
TopScoreDocCollector collector = TopScoreDocCollector.create(numberOfHits, true);
Directory directory = new SimpleFSDirectory(new File(LocationOfDirectory));
IndexSearcher searcher = new IndexSearcher(IndexReader.open(directory);

WildcardQuery q = new WildcardQuery(new Term("Street", "the crescent");

searcher.search(q, collector);
ScoreDoc[] hits = collector.topDocs().scoreDocs;

Я попытался поменять местами шаблонный запрос для запроса фразы, сначала со всей строкой, а затем разделить строку на пустое пространство и обернуть их в BooleanQuery следующим образом:

String term = "the crescent";
BooleanQuery b = new BooleanQuery();
PhraseQuery p = new PhraseQuery();
String[] tokens = term.split(" ");
for(int i = 0 ; i < tokens.length ; ++i)
{
    p.add(new Term("Street", tokens[i]));
}
b.add(p, BooleanClause.Occur.MUST);

Однако это не сработало. Я попытался использовать KeywordAnalyzer вместо StandardAnalyzer, но затем все другие типы поиска перестали работать. Я попытался заменить пробелы другими символами (+ и @) и преобразовать запросы в и из этой формы, но это все равно не работает. Я думаю, что это не работает, потому что + и @ являются специальными символами, которые не индексируются, но я не могу найти список где-нибудь, какие символы такие.

Я начинаю немного сходить с ума, кто-нибудь знает, что я делаю не так?

Спасибо, Rik

Ответы [ 4 ]

13 голосов
/ 31 января 2012

Причина, по которой вы не получаете свои документы обратно, заключается в том, что при индексации вы используете StandardAnalyzer, который преобразует токены в строчные буквы и удаляет стоп-слова. Таким образом, единственный термин, который индексируется для вашего примера, это «полумесяц». Однако подстановочные запросы не анализируются, поэтому в качестве обязательной части запроса указывается «the». То же самое касается запросов фраз в вашем сценарии.

KeywordAnalyzer, вероятно, не очень подходит для вашего варианта использования, потому что он принимает содержимое всего поля как один токен. Вы можете использовать SimpleAnalyzer для поля улицы - оно разделит ввод на все не-буквенные символы, а затем преобразует их в строчные. Вы также можете рассмотреть возможность использования WhitespaceAnalyzer с LowerCaseFilter. Вам нужно попробовать разные варианты и определить, что лучше всего подходит для ваших данных и пользователей.

Кроме того, вы можете использовать разные анализаторы для каждого поля (например, с PerFieldAnalyzerWrapper), если изменение анализатора для этого поля прерывает другие поиски.

7 голосов
/ 31 января 2012

Я обнаружил, что моя попытка сгенерировать запрос без использования QueryParser не работала, поэтому я перестал пытаться создавать свои собственные запросы и вместо этого использовал QueryParser. Все рекомендации, которые я видел в Интернете, показали, что вы должны использовать тот же Analyzer в QueryParser, который вы используете во время индексации, поэтому я использовал StandardAnalyzer для сборки QueryParser.

Это работает в этом примере, потому что StandardAnalyzer удаляет слово "the" с улицы "полумесяц" во время индексации, и, следовательно, мы не можем искать его, потому что его нет в индексе.

Однако, если мы выберем поиск "Дорога в роще", у нас возникнет проблема с готовой функциональностью, а именно, что запрос вернет все результаты, содержащие либо "Grove", либо "Дорога". , Это легко исправить, настроив QueryParser так, чтобы его операцией по умолчанию было И вместо ИЛИ.

В итоге правильное решение было следующим:

int numberOfHits = 200;
String LocationOfDirectory = "C:\\dir\\index";
TopScoreDocCollector collector = TopScoreDocCollector.create(numberOfHits, true);
Directory directory = new SimpleFSDirectory(new File(LocationOfDirectory));
IndexSearcher searcher = new IndexSearcher(IndexReader.open(directory);

StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_35);

//WildcardQuery q = new WildcardQuery(new Term("Street", "the crescent");
QueryParser qp = new QueryParser(Version.LUCENE_35, "Street", analyzer);
qp.setDefaultOperator(QueryParser.Operator.AND);

Query q = qp.parse("grove road");

searcher.search(q, collector);
ScoreDoc[] hits = collector.topDocs().scoreDocs;
0 голосов
/ 01 мая 2017

Нет необходимости использовать какие-либо Analyzer здесь, потому что Hibernate неявно использует StandardAnalyzer, который будет разбивать слова на основе white spaces, поэтому решение здесь установлено для Analyze на NO, которое будет выполняться автоматически Multi Phrase Search

 @Column(name="skill")
    @Field(index=Index.YES, analyze=Analyze.NO, store=Store.NO)
    @Analyzer(definition="SkillsAnalyzer")
    private String skill;
0 голосов
/ 31 января 2012

Если вы хотите, чтобы точные слова соответствовали улице, вы можете установить поле "Улица" NOT_ANALYZED, которое не будет фильтровать стоп-слово "the".

doc.add(new Field("Street", "the crescent", Field.Store.YES, Field.Index.Not_Analyzed);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...