【问题标题】:How to search fields with wildcard and spaces in Hibernate Search如何在 Hibernate Search 中使用通配符和空格搜索字段
【发布时间】:2013-02-23 11:21:45
【问题描述】:

我有一个搜索框,它根据给定的输入对标题字段执行搜索,因此用户推荐了所有可用的标题,以插入的文本开头。它基于 Lucene 和 Hibernate Search。在输入空间之前它工作正常。然后结果消失。例如,我希望“Learning H”给我“Learning Hibernate”作为结果。但是,这不会发生。你能告诉我我应该在这里用什么吗?

查询生成器:

QueryBuilder qBuilder = fullTextSession.getSearchFactory()
        .buildQueryBuilder().forEntity(LearningGoal.class).get();
  Query query = qBuilder.keyword().wildcard().onField("title")
        .matching(searchString + "*").createQuery();

  BooleanQuery bQuery = new BooleanQuery();
  bQuery.add(query, BooleanClause.Occur.MUST);
  for (LearningGoal exGoal : existingGoals) {
     Term omittedTerm = new Term("id", String.valueOf(exGoal.getId()));
     bQuery.add(new TermQuery(omittedTerm), BooleanClause.Occur.MUST_NOT);
  }
  @SuppressWarnings("unused")
  org.hibernate.Query hibQuery = fullTextSession.createFullTextQuery(
        query, LearningGoal.class);

休眠类

@AnalyzerDef(name = "searchtokenanalyzer",tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
filters = {
  @TokenFilterDef(factory = StandardFilterFactory.class),
  @TokenFilterDef(factory = LowerCaseFilterFactory.class),
  @TokenFilterDef(factory = StopFilterFactory.class,params = { 
      @Parameter(name = "ignoreCase", value = "true") }) })
      @Analyzer(definition = "searchtokenanalyzer")
public class LearningGoal extends Node {

【问题讨论】:

  • 将查询打印到输出肯定会对您有所帮助..
  • 确实有用,但没有帮助我理解为什么我没有结果。例如,我有一个名为“学习概率论”的学习目标。对于输入字符串“learning p”,两个查询的输出是 bQuery:+title:learning p* hibQuery:FullTextQueryImpl(title:learning p*)。如果输入字符串是“学习”,它会找到值。
  • 我也尝试用 ? 替换空格,但没有给出结果。

标签: java hibernate lucene full-text-search hibernate-search


【解决方案1】:

SQL 使用不同于任何终端的通配符。在 SQL 中,'%' 替换零次或多次出现的任何字符(在终端中,您使用 '*' 代替),并且下划线 '_' 仅替换一个字符(在终端中,您使用 '?' 代替)。 Hibernate 不翻译通配符。

因此,在第二行中,您必须将 matching(searchString + "*") 替换为

  matching(searchString + "%")

【讨论】:

  • 你确定吗?在此之后,即使 searchString 中没有空格,它也不会给我任何结果。以前(带*)我有一些结果,直到searchString 中出现空格。我不知道这个HibernateSearch 与SQL 有什么关系?它对未存储在数据库中的 Lucene 索引执行搜索,所以我不确定它是否使用 SQL 语法。
  • 对于Hibernate + SQL我确定,但我没有使用Lucene,也不知道Lucene引擎对输入做了什么。
  • 我明白了。您认为这是常规的数据库查询。但是,Hibernate Search 使用 Lucene 查询来搜索 lucene 索引,其语法与 SQL lucenetutorial.com/lucene-query-syntax.html 不同
【解决方案2】:

我找到了解决此问题的方法。这个想法是对输入字符串进行标记并删除停用词。对于最后一个标记,我使用关键字通配符创建了一个查询,对于之前的所有单词,我创建了一个 TermQuery。这是完整的代码

    BooleanQuery bQuery = new BooleanQuery();
    Session session = persistence.currentManager();
    FullTextSession fullTextSession = Search.getFullTextSession(session);
    Analyzer analyzer = fullTextSession.getSearchFactory().getAnalyzer("searchtokenanalyzer");
    QueryParser parser = new QueryParser(Version.LUCENE_35, "title", analyzer);
    String[] tokenized=null;
    try {
    Query query=    parser.parse(searchString);
    String cleanedText=query.toString("title");
     tokenized = cleanedText.split("\\s");

    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    QueryBuilder qBuilder = fullTextSession.getSearchFactory()
            .buildQueryBuilder().forEntity(LearningGoal.class).get();
    for(int i=0;i<tokenized.length;i++){
         if(i==(tokenized.length-1)){
            Query query = qBuilder.keyword().wildcard().onField("title")
                    .matching(tokenized[i] + "*").createQuery();
                bQuery.add(query, BooleanClause.Occur.MUST);
        }else{
            Term exactTerm = new Term("title", tokenized[i]);
            bQuery.add(new TermQuery(exactTerm), BooleanClause.Occur.MUST);
        }
    }
        for (LearningGoal exGoal : existingGoals) {
        Term omittedTerm = new Term("id", String.valueOf(exGoal.getId()));
        bQuery.add(new TermQuery(omittedTerm), BooleanClause.Occur.MUST_NOT);
    }
    org.hibernate.Query hibQuery = fullTextSession.createFullTextQuery(
            bQuery, LearningGoal.class);

【讨论】:

  • 您能否添加更多解释?到目前为止我还不明白。为什么你对最后一个令牌使用不同的查询?并且请修改您的示例,这已经足够清楚了。为什么existingGoals 是必需的?
  • 假设我们有标题“Hibernate Search”。当用户输入“Hibernate Se”时,第一个标记将是“Hibernate”,我们采用确切的术语,因为我们知道用户输入了他想要的整个单词,因为他已经开始输入另一个单词。对于第二个单词“se”,因为我们知道用户可能没有完成输入,所以我们使用通配符来确保他不在单词的中间,这正是这里的情况。因此,最后一个单词的查询将涵盖以“se”开头的所有内容,并且用户之前输入的所有单词都将用作确切的术语。
  • 对于第二个问题(existingGoals),这是我的用例场景非常具体的问题。我想从搜索结果中排除用户已经添加到他的选定项目列表中的那些标题,所以这些现有目标实际上是应该被忽略的标题,你可能不需要它。
  • 这里确实很有意义。我刚刚将您的循环用于我的用例。 :) 谢谢!
  • 谢谢,兄弟。帮了大忙。
猜你喜欢
  • 1970-01-01
  • 2015-07-18
  • 1970-01-01
  • 1970-01-01
  • 2018-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-26
相关资源
最近更新 更多