2010-09-23 8 views
2

Использование аннотаций для спящего режима (в основном только @Field(index = Index.TOKENIZED)) Я проиндексировал ряд полей, связанных с сохранившимся классом, называемым Compound. Я установил текстовый поиск по всем индексированным полям, используя MultiFieldQueryParser, который до сих пор работал нормально.Согласование подстановочных знаков Lucene на химических обозначениях (?)

Среди полей, индексированных и с возможностью поиска является поле, называемое compoundName, со значениями выборки:

  • 3-Hydroxyflavone
  • 6,4'-Dihydroxyflavone

Когда я искать любое из этих значений в полном родственном соединении экземпляры возвращаются. Однако проблемы возникают, когда я использую частичное имя и ввести символы:

  • поиски 3-Hydroxyflav* все еще дает правильный удар, но
  • ищет 6,4'-Dihydroxyflav* не может найти что-нибудь.

Теперь, когда я совсем новичок в Lucene/Hibernate-поиска, я не совсем уверен, где смотреть на данный момент .. Я думаю, что это, возможно, что-то делать с ' настоящее во втором запросе , но я не знаю, как это сделать. Должен ли я смотреть в токенизаторы/анализы/QueryParsers или что-то еще?

Или может кто-нибудь сказать мне, как я могу получить второй поиск подстановочных знаков, желательно, не нарушая поведение MultiField-поиска?

Я использую Hibernate-Search 3.1.0.GA & Lucene-core 2.9.3.


Некоторые соответствующие кодовые биты, чтобы проиллюстрировать мой текущий подход:

Соответствующие части индексированного класса соединения:

@Entity 
@Indexed 
@Data 
@EqualsAndHashCode(callSuper = false, of = { "inchikey" }) 
public class Compound extends DomainObject { 
    @NaturalId 
    @NotEmpty 
    @Length(max = 30) 
    @Field(index = Index.TOKENIZED) 
    private String     inchikey; 

    @ManyToOne 
    @IndexedEmbedded 
    private ChemicalClass   chemicalClass; 

    @Field(index = Index.TOKENIZED) 
    private String     commonName; 
... 
} 

Как я в настоящее время поиска над индексированных полей:

String[] searchfields = Compound.getSearchfields(); 
MultiFieldQueryParser parser = 
    new MultiFieldQueryParser(Version.LUCENE_29, searchfields, new StandardAnalyzer(Version.LUCENE_29)); 
FullTextSession fullTextSession = Search.getFullTextSession(getSession()); 
FullTextQuery fullTextQuery = 
    fullTextSession.createFullTextQuery(parser.parse("searchterms"), Compound.class); 
List<Compound> hits = fullTextQuery.list(); 

ответ

2

Я думаю, что ваша проблема - это сочетание анализатора и проблем языка запросов. Трудно сказать, что именно вызывает проблему. Чтобы это выяснить, я рекомендую вам проинспектировать ваш индекс с помощью инструмента индекса Lucene Luke.

Поскольку в вашей конфигурации Hibernate Search вы не используете пользовательский анализатор по умолчанию - StandardAnalyzer - используется. Это было бы согласуется с тем, что вы используете StandardAnalyzer в конструкторе MultiFieldQueryParser (всегда используйте тот же анализатор для индексирования и поиска!). Я не очень уверен в том, как «6,4'-Дигидроксифлавон» получает токенизацию от StandardAnalyzer. Это первое, что вам нужно выяснить.Например, Javadoc говорит:

Разделяет слова на дефис, если нет число в знак, в этом случае вся токен интерпретируется как номер продукта и не расщепляется.

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

Следующий парсер запросов. Убедитесь, что вы поняли синтаксис запроса - Lucene query syntax. Некоторые символы имеют особое значение, например, «-». Возможно, ваш запрос анализируется неправильно.

В любом случае, первый шаг os, чтобы узнать, как ваши химические имена становятся токенированными. Надеюсь, это поможет.

+0

FYI, я быстро проверил, как StandardAnalyzer размечает свои примеры. «3-Гидроксифлавон», похоже, подпадает под упомянутое выше правило продукта. Он становится единственным символом «3-гидроксифлавон». «6,4'-Дигидроксифлавон», с другой стороны, превращается в два токена «6,4» и «дигидроксифлавон». – Hardy

+0

Ничего себе, спасибо! Я просто пытался использовать Luke здесь, чтобы проверить то же самое. Gues это означает, что мне нужно использовать альтернативный анализатор? (Я пытался установить поле UN_TOKENIZED, но это даже ломает первый пример поиска.) – Tim

+0

Кажется, StandardTokenizer разбивает слова на апострофы .. Это, по крайней мере, указывает на проблему, но мне потребуется некоторое время, чтобы исправить это .. :) Спасибо за помощь! – Tim

4

Использовать WhitespaceAnalyzer вместо StandardAnalyzer. Он будет просто разбит на пробелы, а не на запятые, дефисы и т. Д. (Это не будет содержать их ниже, поэтому вам нужно будет создать собственную цепочку пробелов + строчный регистр, если вы хотите, чтобы ваш поиск был нечувствительным к регистру). Если вам нужно делать что-то по-разному для разных полей, вы можете использовать PerFieldAnalyzer.

Вы не можете просто установить его в un-tokenized, потому что это будет интерпретировать весь текст вашего тела как один токен.

+0

Хмм, это звучит многообещающе, но первоначальное тестирование пока еще не разрешило проблему. Возможно, мне придется попробовать цепочку фильтров и PerFieldAnalyzer .. Будет отчитываться, как только я это сделаю. – Tim

1

я написал свой собственный анализатор:

import java.util.Set; 
import java.util.regex.Pattern; 

import org.apache.lucene.index.memory.PatternAnalyzer; 
import org.apache.lucene.util.Version; 

public class ChemicalNameAnalyzer extends PatternAnalyzer { 

    private static Version version = Version.LUCENE_29; 
    private static Pattern pattern = compilePattern(); 
    private static boolean toLowerCase = true; 
    private static Set stopWords = null; 

    public ChemicalNameAnalyzer(){ 
     super(version, pattern, toLowerCase, stopWords); 
    } 

    public static Pattern compilePattern() { 
     StringBuilder sb = new StringBuilder(); 
     sb.append("(-{0,1}\\(-{0,1})");//Matches an optional dash followed by an opening round bracket followed by an optional dash 
     sb.append("|");//"OR" (regex alternation) 
     sb.append("(-{0,1}\\)-{0,1})"); 
     sb.append("|");//"OR" (regex alternation) 
     sb.append("((?<=([a-zA-Z]{2,}))-(?=([^a-zA-Z])))");//Matches a dash ("-") preceded by two or more letters and succeeded by a non-letter 
     return Pattern.compile(sb.toString()); 
    } 
}