如何配置Hibernate Search以查找带重音的单词

时间:2014-03-04 15:37:58

标签: lucene hibernate-search

我需要在我使用Spring(4.0.2)/ Hibernate(4.3.1)/ MySQL实现的网站上实现全局搜索。我决定使用Hibernate Search(4.5.0)。

这似乎工作正常,但只有在我搜索确切的模式时才会正常工作。

想象一下,我在索引字段上有以下文字: “一个组织做Capuchinho e做Lobo Mau”

1)如果我搜索“história”或“lobo mau”,查询将检索相应的索引实体,如我所料。

2)如果我搜索“historia”或“lobos maus”,搜索将不会检索该实体。

据我所知,应该可以配置Hibernate Search来执行比这更聪明的搜索。任何人都能指出我正确的方向来实现这一目标吗?请参阅下面我执行的实现的关键方面。谢谢!

这是“父”索引实体

@Entity
@Table(name="NEWS_HEADER")
@Indexed
public class NewsHeader implements Serializable {

static final long serialVersionUID = 20140301L;

private int                 id;
private String              articleHeader;
private String              language;
private Set<NewsParagraph>  paragraphs = new HashSet<NewsParagraph>();

/**
 * @return the id
 */
@Id
@Column(name="ID")
@GeneratedValue(strategy=GenerationType.AUTO)
@DocumentId
public int getId() {
    return id;
}
/**
 * @param id the id to set
 */
public void setId(int id) {
    this.id = id;
}
/**
 * @return the articleHeader
 */
@Column(name="ARTICLE_HEADER")
@Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
public String getArticleHeader() {
    return articleHeader;
}
/**
 * @param articleHeader the articleHeader to set
 */
public void setArticleHeader(String articleHeader) {
    this.articleHeader = articleHeader;
}
/**
 * @return the language
 */
@Column(name="LANGUAGE")
public String getLanguage() {
    return language;
}
/**
 * @param language the language to set
 */
public void setLanguage(String language) {
    this.language = language;
}
/**
 * @return the paragraphs
 */
@OneToMany(mappedBy="newsHeader", fetch=FetchType.EAGER, cascade=CascadeType.ALL)
@IndexedEmbedded
public Set<NewsParagraph> getParagraphs() {
    return paragraphs;
}
// Other standard getters/setters go here

这是IndexedEmbedded实体

@Entity
@Table(name="NEWS_PARAGRAPH")
public class NewsParagraph implements Serializable {

static final long serialVersionUID = 20140302L;

private int         id;
private String      content;
private NewsHeader  newsHeader;

/**
 * @return the id
 */
@Id
@Column(name="ID")
@GeneratedValue(strategy=GenerationType.AUTO)
public int getId() {
    return id;
}
/**
 * @param id the id to set
 */
public void setId(int id) {
    this.id = id;
}
/**
 * @return the content
 */
@Column(name="CONTENT")
@Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
public String getContent() {
    return content;
}
// Other standard getters/setters go here

这是我的搜索方法,在我的SearchDAOImpl上实现

public class SearchDAOImpl extends DAOBasics implements SearchDAO {
    ...
    public List<NewsHeader> searchParagraph(String patternStr) {

    Session session = null;

    Transaction tx;

    List<NewsHeader> result = null;

    try {
        session = sessionFactory.getCurrentSession();
        FullTextSession fullTextSession = Search.getFullTextSession(session);
        tx = fullTextSession.beginTransaction();

        // Create native Lucene query using the query DSL
        QueryBuilder queryBuilder = fullTextSession.getSearchFactory()
            .buildQueryBuilder().forEntity(NewsHeader.class).get();

        org.apache.lucene.search.Query luceneSearchQuery = queryBuilder
            .keyword()
            .onFields("articleHeader", "paragraphs.content")
            .matching(patternStr)
            .createQuery();

        // Wrap Lucene query in a org.hibernate.Query
        org.hibernate.Query hibernateQuery = 
            fullTextSession.createFullTextQuery(luceneSearchQuery, NewsHeader.class, NewsParagraph.class);

        // Execute search
        result = hibernateQuery.list();

    } catch (Exception xcp) {
        logger.error(xcp);
    } finally {

        if ((session != null) && (session.isOpen())) {
            session.close();
        }
    }
    return result;
}
...
}

3 个答案:

答案 0 :(得分:2)

您可以配置,也可以使用标准语言分析器,例如PortugueseAnalyzer。我建议从现有的分析器开始,并在必要时创建自己的分析器,将其作为调整过滤器链的起点。

您可以使用字段的@Analyzer注释进行设置:

@Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO, analyzer = @Analyzer(impl = org.apache.lucene.analysis.pt.PortugueseAnalyzer.class))

或者您可以将该分析器设置为该类的默认值,如果您放置@analyzer注释,则代之以该类的头部。

答案 1 :(得分:2)

这就是我最终要解决的问题。

在实体级别配置AnalyzerDef。在其中,使用LowerCaseFilterFactory,ASCIIFoldingFilterFactory和SnowballPorterFilterFactory来实现我需要的过滤类型。

@AnalyzerDef(name = "customAnalyzer",
  tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
  filters = {
    @TokenFilterDef(factory = LowerCaseFilterFactory.class),
    @TokenFilterDef(factory = ASCIIFoldingFilterFactory.class),
    @TokenFilterDef(factory = SnowballPorterFilterFactory.class)
})
public class NewsHeader implements Serializable {
...
}

为我要索引的每个字段添加此表示法,在Parent实体或其IndexedEmbedded对应项中,以使用上面定义的分析器。

@Field(index=Index.YES, store=Store.NO)
@Analyzer(definition = "customAnalyzer")

您需要重新索引或重新插入实体,才能使分析仪生效。

答案 2 :(得分:1)

如果你想搜索重音字符并在结果中找到相同的普通关键字,那么你必须在分析器中实现ASCIIFoldingFilterFactory类

local server

@Analyzer(definition =“customAnalyzer”)适用于实体或字段