当前位置: 首页 > 知识库问答 >
问题:

Hibernate/Lucene搜索:通配符查询

阎知
2023-03-14

我使用这个分析器创建了一个模型:

@Indexed
@AnalyzerDef(name = "abAnalyzer", tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class), filters =
{
    @TokenFilterDef(factory = StandardFilterFactory.class),
    @TokenFilterDef(factory = LowerCaseFilterFactory.class),
    @TokenFilterDef(factory = StopFilterFactory.class, params =
    {
        @Parameter(name = "ignoreCase", value = "true")
    })
})
public class Foo
{
    ...
    @Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO)
    @Analyzer(definition = "abAnalyzer")
    private String name;

    ...
}

我实现了如下所示的查询。我得到了所有预期的结果,除了像“A.B.C”这样的结果。我做错了什么?我哪里误解了事情?

public List<Foo> getResults(final String searchName)
{
    Session session = this.sessionFactory.openSession();
    FullTextSession fullTextSession = Search.getFullTextSession(session);
    Transaction tx = fullTextSession.beginTransaction();

    BooleanQuery bQuery = new BooleanQuery();
    Analyzer analyzer = fullTextSession.getSearchFactory().getAnalyzer("abAnalyzer");

    QueryParser qp = new QueryParser(Version.LUCENE_36, "name", analyzer);
    String cleanedText = qp.parse(searchName).toString("name");
    String[] tokenized = cleanedText.split(""); // split on each character

    QueryBuilder qBuilder = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(Foo.class).get();

    org.apache.lucene.search.Query query = qBuilder.keyword().wildcard().onField("name").matching("*" + cleanedText + "*").createQuery();
    bQuery.add(query, BooleanClause.Occur.SHOULD);

    query = qBuilder.keyword().wildcard().onField("name").matching("*" + createSearchString(cleanedText) + "*").createQuery();
    bQuery.add(query, BooleanClause.Occur.SHOULD);

    org.hibernate.Query hibQuery = fullTextSession.createFullTextQuery(bQuery, Company.class);    
    return hibQuery.list();
}

....

private String createSearchString(final String name)
{
    StringBuilder searchName = new StringBuilder("");
    for (int i = 0; i < name.length(); i++)
    {
        if (searchName.length() > 0)
        {
            searchName.append("?");
        }
        searchName.append(name.charAt(i));
    }

    return searchName.toString();
}

我的代码基于以下资源:

共有1个答案

单于越
2023-03-14

我想我找到了解决办法...Lucene索引是基于小写字符串生成的,索引中的“特殊”字符被删除。

于是,我把模型改成:

@Indexed
@AnalyzerDef(name = "abAnalyzer", charFilters =
{
    @CharFilterDef(factory = PatternReplaceCharFilterFactory.class, params =
    {
        @Parameter(name = "pattern", value = Company.PATTERN),
        @Parameter(name = "replacement", value = Company.REPLACEMENT_PATTERN)
    })
 }, tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class), filters =
{
    @TokenFilterDef(factory = StandardFilterFactory.class), @TokenFilterDef(factory = LowerCaseFilterFactory.class),
})
public class Foo
{
    public static final String PATTERN = "(A-Z)*[\\/\\.\\-'+&, ](A-Z)*";
    public static final String REPLACEMENT_PATTERN = "$1$2";

    @Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO)
    @Analyzer(definition = "abAnalyzer")
    private String name;

    ....
}

为了进行查询,我实现了以下内容:

public List<Foo> getResults(final String searchName)
{
    List<Foo> result = new ArrayList<>();

    // remove "special chars from searchName"
    String searchName = name.replaceAll(Company.PATTERN, Company.REPLACEMENT_PATTERN);

    Session session = this.sessionFactory.openSession();
    try
    {
        FullTextSession fullTextSession = Search.getFullTextSession(session);
        Transaction tx = fullTextSession.beginTransaction();
        Analyzer analyzer = fullTextSession.getSearchFactory().getAnalyzer("abAnalyzer");

        QueryParser qp = new QueryParser(Version.LUCENE_36, "name", analyzer);
        String cleanedText = qp.parse(searchName).toString("name");

        BooleanQuery bQuery = new BooleanQuery();
        bQuery.add(new WildcardQuery(new Term("name", "*" + cleanedText + "*")), BooleanClause.Occur.SHOULD);

        org.hibernate.Query hibQuery = fullTextSession.createFullTextQuery(bQuery, Company.class);

        result = hibQuery.list();
        tx.commit();
    }
    catch (Exception e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    finally
    {
        session.close();
    }

    return result;
}
 类似资料:
  • 我的任务是使用lucene在我们的产品表中搜索。我已经创建了一个索引,正在使用带有多个字段的QueryParser进行搜索,但结果不是我所需要的。我有一个存储为LM10的产品,但如果搜索词是LM 10,我希望能够找到它,但如果搜索词是Fred LM10或Fred LM 10,它也必须能够匹配。你知道我如何在Lucene做到这一点吗。 提前谢谢

  • 我正在使用Hibernate Search/Lucene Intégration开发一个J2E应用程序。我索引文档(和其他实体),并希望对其进行不区分重音的搜索(内容和类的字段)。 这样做好吗?是否没有param或conf属性让FrenchAnalyzer忽略重音? 谢谢

  • 本文向大家介绍solr 通配符搜索,包括了solr 通配符搜索的使用技巧和注意事项,需要的朋友参考一下 示例 name:john* *指示符允许您在搜索词john之后进行匹配0个或多个字符的通配符搜索,将返回包含john,johnson,john's,johnny等的文档。 name:do? ?指示符允许您在搜索项中使用单个字符进行通配符搜索,将返回包含doe,dog,dot等的文档。

  • 下面的lucene查询返回空字符串请帮忙,提前谢谢

  • 异常,我读到写超时锁应该从默认的1秒增加。 ( 有趣的是,以前我没有这个异常,但我正在执行一个在项目上使用Spring的任务。很可能有更多的竞争事务试图访问索引...?我认为我认为Spring事务配置不正确: ) 谢谢, V。

  • 我在我的应用程序中使用Hibernate搜索。其中一个子集合映射为IndexeDemBedded。子对象有两个字段,一个是id,另一个是date(使用date resoultion到毫秒)。当我搜索ID=1(或某个值)并且date等于另一个值时,我会得到第一个和第二个匹配的所有情况的结果。我只想在同一个孩子中获得两个字段匹配的记录,但我在不同的孩子中获得匹配,结果会高得多。下面是代码片段 主类是用