【问题标题】:Hibernate + Lucene - wildard search returning empty resultHibernate + Lucene - 通配符搜索返回空结果
【发布时间】:2016-08-11 01:16:28
【问题描述】:

我写了一篇关于通过通配符搜索数据库表的漂亮 Hibernate 搜索的文章。

所以我已经将它添加到我的 pom.xml 中:

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-search-orm</artifactId>
        <version>5.5.4.Final</version>
    </dependency>

设置目录提供者:

properties.put("hibernate.search.default.directory_provider", "ram");

并在我的实体上定义了对搜索机制可见的索引:

@Entity
@Table(name = "CUSTOM_ENTITY")
@Audited
@Indexed
public class CustomEntity implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    @DocumentId
    private Long id;

    @Column(name = "NAME1", nullable = false)
    @NotEmpty
    @Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO)
    private String name1;

    @Column(name = "NAME2", nullable = false)
    @NotEmpty
    @Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO)
    private String name2;

    @Column(name = "NAME3", nullable = false)
    @NotEmpty
    @Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO)
    private String name3;

    // ...
}

然后我从 SQL 脚本数据库表手动加载 - CUSTOM_ENTITY:

ID |NAME1 |NAME2 |NAME3 |
-------------------------
1  |Test1 |Test1 |Test1 |
2  |Test2 |Test2 |Test2 |
3  |Test3 |Test2 |Test2 |

并在我的存储库中运行代码:

FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);

QueryBuilder qBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(CustomEntity.class).get();

Query luceneQuery = qBuilder.keyword().wildcard().onFields("name1", "name2", "name3").matching("Test").createQuery();
// Query luceneQuery = qBuilder.keyword().wildcard().onFields("name1", "name2", "name3").matching("Test*").createQuery();
// Query luceneQuery = qBuilder.keyword().wildcard().onFields("name1", "name2", "name3").matching("Test%").createQuery();

List test = fullTextEntityManager.createFullTextQuery(luceneQuery, CustomEntity.class).getResultList();

但是每次结果集合都是空的。你知道我是否错过了任何一步吗?我应该使用 Hibernate API 而不是 SQL 脚本加载数据吗?


编辑

在运行查询之前,我手动索引数据:

FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);
try {
    fullTextEntityManager.createIndexer().startAndWait();
} catch (InterruptedException e) {
    e.printStackTrace();
}
QueryBuilder qBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(CustomEntity.class).get();

Query luceneQuery = qBuilder.keyword().wildcard().onFields("name1", "name2", "name3").matching("Test").createQuery();
// Query luceneQuery = qBuilder.keyword().wildcard().onFields("name1", "name2", "name3").matching("Test*").createQuery();
// Query luceneQuery = qBuilder.keyword().wildcard().onFields("name1", "name2", "name3").matching("Test%").createQuery();

List test = fullTextEntityManager.createFullTextQuery(luceneQuery, CustomEntity.class).getResultList();

结果还是一样。

感谢您的帮助。

【问题讨论】:

  • 你在searching 之前做了indexing 吗?您的注释看起来不错,它们应该会自动检测插入的新实体并为其编制索引。但是,对于现有数据,您需要启动海量索引器来重建索引。
  • 另外请记住,当您使用“ram”目录时,您的索引不会被持久化。您是否在索引和查询之间重新启动 Hibernate SessionFactory(或 JPA EntityManager)?

标签: java hibernate lucene hibernate-search


【解决方案1】:

如果您使用 SQL 加载数据,则需要使用 Mass indexer 手动索引数据。见https://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/#search-batchindex-massindexer

如果您使用的是 Hibernate API,它们将被自动编入索引。

【讨论】:

    【解决方案2】:

    问题解决了。问题与骆驼案例“搜索字符串”有关。

    我注意到,即使我将值存储在数据库中,例如:

    ID |NAME1 |NAME2 |NAME3 |
    -------------------------
    1  |Test1 |Test1 |Test1 |
    2  |Test2 |Test2 |Test2 |
    3  |Test3 |Test2 |Test2 |
    

    Lucene 无法通过字符串 Test* 进行搜索:

    Query luceneQuery = qBuilder.keyword().wildcard().onFields("name1", "name2", "name3").matching("Test*").createQuery();
    

    当我将查询更改为:

    Query luceneQuery = qBuilder.keyword().wildcard().onFields("name1", "name2", "name3").matching("test*").createQuery();
    

    一切正常。我还不知道为什么,但它解决了这个问题。

    感谢您的时间和帮助。

    【讨论】:

      【解决方案3】:

      在搜索之前的所有实体having indexed 之后,您需要使用?* 进行正确的通配符查询。字符? 代表单个字符,* 代表任意字符序列:

      假设你有下表:

      ID | NAME1  | NAME2  | NAME3  |
      -------------------------------
      1  | test1  | test1  | test1  |
      2  | test2  | test2  | test2  |
      3  | test3  | test3  | test3  |
      4  | test4A | test4B | test4C |
      

      然后? 将获得 3 个结果,* 将获得 4 个结果。

      Query luceneQuery = qBuilder.keyword()
          .wildcard()
          .onFields("name1", "name2", "name3")
          .matching("test?")  // return {1, 2, 3}
      //  .matching("test*")  // return {1, 2, 3, 4}
      //  .matching("test")   // return {}
          .createQuery();
      

      【讨论】:

        最近更新 更多