Hibernate Search:如何正确使用通配符?

Mau*_*jal 1 lucene hibernate wildcard hibernate-search

对于特定的医疗中心,我有以下查询以全名搜索患者:

MustJunction mj = qb.bool().must(qb.keyword()
    .onField("medicalCenter.id")
    .matching(medicalCenter.getId())
    .createQuery());
for(String term: terms)
    if(!term.equals(""))
       mj.must(qb.keyword()
       .onField("fullName")
       .matching(term+"*")
       .createQuery());
Run Code Online (Sandbox Code Playgroud)

并且它工作得很好,但前提是用户键入患者的完整名字和/或姓氏.

但是,即使用户键入firstname或lastname 的一部分,我也希望能够工作.

例如,如果有一个名为"Bilbo Baggins"的病人,我希望搜索找到他,当用户输入"Bilbo Baggins",Bilbo,"Baggins"时,或者即使他只输入"Bil"或"Bag"

为此,我修改了上面的查询,如下所示:

MustJunction mj = qb.bool().must(qb.keyword()
    .onField("medicalCenter.id")
    .matching(medicalCenter.getId())
    .createQuery());
for(String term: terms)
    if(!term.equals(""))
       mj.must(qb.keyword()
       .wildcard()
       .onField("fullName")
       .matching(term+"*")
       .createQuery());
Run Code Online (Sandbox Code Playgroud)

注意我在调用onField()之前如何添加wildcard()函数

但是,这会中断搜索并返回无结果.我究竟做错了什么?

yro*_*ere 5

简答:不要使用通配符查询,使用自定义分析器EdgeNGramAnalyzerFactory.另外,不要试图自己分析查询(这就是你通过将查询分成术语所做的事情):Lucene会做得更好(特别是a WhitespaceTokenizerFactory,a ASCIIFoldingFilterFactory和a LowercaseFilterFactory).

答案很长:

通配符查询可用作一次性问题的快速简便解决方案,但它们不是非常灵活,可以很快达到极限.特别是,正如@femtoRgon所提到的,这些查询不会被分析,因此大写查询不会与小写名称匹配.

Lucene世界中大多数问题的经典解决方案是在索引时和查询时使用特制的分析器(不一定相同).在您的情况下,您将需要在索引时使用此类分析器:

@AnalyzerDef(name = "edgeNgram",
    tokenizer = @TokenizerDef(factory = WhitespaceTokenizerFactory.class),
    filters = {
            @TokenFilterDef(factory = ASCIIFoldingFilterFactory.class), // Replace accented characeters by their simpler counterpart (è => e, etc.)
            @TokenFilterDef(factory = LowerCaseFilterFactory.class), // Lowercase all characters
            @TokenFilterDef(
                    factory = EdgeNGramFilterFactory.class, // Generate prefix tokens
                    params = {
                            @Parameter(name = "minGramSize", value = "1"),
                            @Parameter(name = "maxGramSize", value = "10")
                    }
            )
    })
Run Code Online (Sandbox Code Playgroud)

在查询时这种类型:

@AnalyzerDef(name = "edgeNGram_query",
    tokenizer = @TokenizerDef(factory = WhitespaceTokenizerFactory.class),
    filters = {
            @TokenFilterDef(factory = ASCIIFoldingFilterFactory.class), // Replace accented characeters by their simpler counterpart (è => e, etc.)
            @TokenFilterDef(factory = LowerCaseFilterFactory.class) // Lowercase all characters
    })
Run Code Online (Sandbox Code Playgroud)

索引分析器将"Mauricio Ubilla Carvajal"转换为此令牌列表:

  • 圣莫尔
  • 马利
  • mauric
  • maurici
  • ü
  • UB
  • ...
  • ubilla
  • C
  • CA
  • ...
  • 卡瓦哈尔

并且查询分析器将查询"mau UB"变为["mau","ub"],这将匹配索引名称(两个标记都存在于索引中).

请注意,您显然必须将分析仪分配到该字段.对于索引部分,使用@Analyzer注释完成.对于查询部分,你将不得不使用overridesForField的查询生成器如图所示这里