Не удается сопоставить подстановочный знак Lucene в химических обозначениях (?) - PullRequest
2 голосов
/ 23 сентября 2010

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

Среди индексируемых и доступных для поиска полей есть поле под названием componentName с примерами значений:

  • 3-Hydroxyflavone
  • 6,4'-Dihydroxyflavone

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

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

Теперь, когда я довольно новичок в Lucene / Hibernate-search, я не совсем уверен, где искать этот момент ... Я думаю, что это может иметь какое-то отношение к ', присутствующему во втором запросе, но я не знаю, как поступить .. Стоит ли искать токенизаторы / анализаторы / 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();

Ответы [ 3 ]

4 голосов
/ 24 сентября 2010

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

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

2 голосов
/ 24 сентября 2010

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

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

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

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

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

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

1 голос
/ 24 марта 2011

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

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());
    }
}
...