且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何使用JPA + MySQL在Spring Boot中实现全文搜索

更新时间:2022-05-09 17:38:04

您可以使用休眠搜索,当您将实体发送到数据库时,该库会插入Hibernate ORM,以便在文件系统上即时将您的实体索引到Lucene索引中.请参阅入门指南.

You can use Hibernate Search, a library that plugs into Hibernate ORM to index your entities into a Lucene index on the filesystem, on the fly, when you send them to your database. See the Getting started guide.

(如今,Hibernate Search还支持将Elasticsearch用作后端;它将自动在Elasticsearch或本地Lucene索引中复制数据库的一部分,无论您选择哪个.)

( Nowadays Hibernate Search also supports using Elasticsearch as a backend; it will automatically duplicate part of your database in Elasticsearch OR in a local Lucene index, whichever you chose.)

查询Lucene/Elasticsearch索引与查询数据库有点不同,因此您不能像通常那样使用HQL或Criteria.Hibernate Search提供了自己的查询DSL.

Querying the Lucene/Elasticsearch index is a bit different than querying the database, so you cannot use HQL or Criteria like you usually would. Hibernate Search offers its own query DSL.

如果要在存储库中使用自动生成的方法实现,则可以依赖Snowdrop ,它是Hibernate Search/Spring Data的集成,但是已经有一段时间没有更新了.

If you want to use auto-magically generated method implementations in your repository, you can rely on Snowdrop, which is a Hibernate Search / Spring Data integration, but it hasn't been updated in a while.

您***的选择可能是在存储库界面中定义查询方法,然后使用Hibernate Search API自己实现它们.它实际上并没有那么复杂,通常建议将其用于最明显的查询之外的所有查询.参见 Spring Data JPA文档.

Your best bet is probably to define query methods in your repository interface, then implement them yourself using Hibernate Search APIs. It's really not that complicated, and it's generally recommended for all but the most obvious queries. See the Spring Data JPA documentation.

基本上,您会看到类似下面的代码片段.请记住,在此之前您需要重新索引数据库!请参阅入门指南有关更多信息.

Essentially you'll have something like the snippet below. Remember that you will need to reindex your database before this works! See the getting started guide for more information.

使用Hibernate Search 6 +:

With Hibernate Search 6+:

@Indexed // Add this
public class Product {

    private Long id;    

    @FullTextField // And this
    private String name;

    @FullTextField // And this
    private String description;

}

public interface ProductRepository extends CrudRepository<Product, Long>, CustomizedProductRepository {
  // Declare automatically generated methods here
}


public interface CustomizedProductRepository {
  List<Product> search(String terms, int limit, int offset);
}



public class CustomizedProductRepositoryImpl implements CustomizedProductRepository {

  @PersistenceContext
  private EntityManager em;

  @Override
  public List<Product> search(String terms, int limit, int offset) {
    return Search.session(em).search(Product.class)
            .where(f -> f.match()
                    .fields("name", "description")
                    .matching(terms))
            .fetchHits(offset, limit);
  }
}

与Hibernate Search 5配合使用:

OR with Hibernate Search 5:

@Indexed // Add this
public class Product {

    private Long id;    

    @Field // And this
    private String name;

    @Field // And this
    private String description;

}

public interface ProductRepository extends CrudRepository<Product, Long>, CustomizedProductRepository {
  // Declare automatically generated methods here
}


public interface CustomizedProductRepository {
  List<Product> search(String terms, int limit, int offset);
}



public class CustomizedProductRepositoryImpl implements CustomizedProductRepository {

  @PersistenceContext
  private EntityManager em;

  @Override
  public List<Product> search(String terms, int limit, int offset) {
    FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);

    QueryBuilder queryBuilder = fullTextEntityManager.getSearchFactory()
        .buildQueryBuilder().forEntity(Product.class).get();
    org.apache.lucene.search.Query luceneQuery = queryBuilder
        .keyword()
        .onFields("name", "description")
        .matching(terms)
        .createQuery();

    // wrap Lucene query in a javax.persistence.Query
    javax.persistence.Query jpaQuery =
        fullTextEntityManager.createFullTextQuery(luceneQuery, Product.class);

    jpaQuery.setMaxResults(limit);
    jpaQuery.setFirstResult(offset);

    // execute search
    return jpaQuery.getResultList();
  }
}