【问题标题】:How to configure Hibernate Search to find words with accents如何配置 Hibernate Search 以查找带有重音符号的单词
【发布时间】:2014-03-04 15:37:58
【问题描述】:

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

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

想象一下,我在索引字段上有以下文本: "A história do Capuchinho e do 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;
}
...
}

【问题讨论】:

    标签: lucene hibernate-search


    【解决方案1】:

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

    在实体级别配置 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 {
    ...
    }
    

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

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

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

    【讨论】:

      【解决方案2】:

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

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

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

      或者您可以将该分析器设置为该类的默认值,如果您将 @analyzerannotation 设置为类的头部。

      【讨论】:

      • 非常感谢 femtoRgon。我最终没有使用葡萄牙语特定的分析器(我的网站已本地化为不同的语言),但这个问题的解决方案确实与配置合适的过滤器链有关。因此,我会将您的回答标记为已接受。我今天学到了很多关于 Hibernate Search / Lucene 的知识,我觉得这只是其中的 5%... :)
      【解决方案3】:

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

      @AnalyzerDef(name = "customAnalyzer",
      tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
      
      filters = {
        @TokenFilterDef(factory = LowerCaseFilterFactory.class),
        @TokenFilterDef(factory = ASCIIFoldingFilterFactory.class),
        @TokenFilterDef(factory = StopFilterFactory.class, params = {
                @Parameter(name="words", value= "com/ik/resource/stoplist.properties" ),
                @Parameter(name="ignoreCase", value="true")
            })
      })
      

      @Analyzer(definition = "customAnalyzer") 应用于实体或字段

      【讨论】:

        猜你喜欢
        • 2022-12-14
        • 2010-11-28
        • 2010-11-29
        • 2015-02-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-07
        • 2011-08-29
        相关资源
        最近更新 更多