分享

Elasticsearch实践(二)在Springboot微服务中集成搜索服务【面试+工作】

 Java帮帮 2020-01-02


Elasticsearch实践(二)在Springboot微服务中集成搜索服务【面试+工作】

Elasticsearch官方API

Elasticsearch提供了多种api。可以直接使用官方提供的Java API进行使用。ElasticSearc Java API https://www./guide/en/elasticsearch/client/java-api/current/index.html  。如果是使用Spring框架的项目,还可以用spring-data-elasticsearch的api。基于spring可以使用Annotation,索引文档不需要任何xml式的配置。而且使用上非常简便。其存储、查询接口继承了JpaRepository,所以对于引入JPA的项目来说,上手非常快。 
Elasticsearch也提供了http协议的API,资源API风格是restful的,所以也都比较好记忆。在有需要的场景时查官网是最快的。

Springboot项目中使用spring-data-elasticsearch框架集成

Springboot项目集成elasticsearch,可以使用spring-data-elasticsearch。官方链接: 
spring-data-elasticsearch Doc  http://docs./spring-data/elasticsearch/docs/current/reference/html/#project  熟悉JPA以及使用过Spring-data-common项目的开发者,应该很快会上手spring-data-elasticsearch。首先要做的就是在gradle项目中,引入‘org.springframework.data:spring-data-elasticsearch:2.1.3.RELEASE’以及‘org.springframework.boot:spring-boot-starter-data-elasticsearch:your_springboot_version’ 。在我们对于索引数据的crud操作api中,主要用的是ElasticsearchRepository 接口,其继承与spring-data的基础repository包的接口CrudRepository。先看一下接口的主要方法:

其对于Elasticsearch的文档(@Document)的数据的操作就类似于JPA中对于数据库表(@Entity)的接口。可以用findByXX的方式进行查询,也可以自定义@Query()方式进行查询。在开发的过程中,对于一些特殊的查询场景,可以查询spring-data-elasticsearch源码中的示例,基本包含了各种场景的API,项目git:spring-data-elasticsearch Git https://github.com/spring-projects/spring-data-elasticsearch 

使用spring-boot-starter-data-elasticsearch做启动时搜索服务的配置

使用Springboot,可以在启动时对很多服务Bean进行注入。一下是通过Autowire方式,使用spring-boot-starter-data-elasticsearch:2.1.3.RELEASE来处理基于Springboot的微服务启动时连接Elasticsearch集群,以及注入应用代码需要使用的 ElasticsearchTemplate。Configuration类如下:

使用spring-data-elasticsearch基于注解的示例API

创建索引和文档,同JPA的 @Entity@Table,可以通过在搜索的文档实体类添加@Document注解的方式,在启动Springboot应用时会直接创建以及更新Elasticsearch的index以及document。 
下面创建一个示例。示例中包含两个Document,一个是OrderDocument,一个是DetailOrderDocument。示例中OrderDocument和DetailOrderDocument是parent-child关联,可以参考官方对于p-c的描述:indexing-parent-child  https://www./guide/en/elasticsearch/guide/current/indexing-parent-child.html  。Elasticsearch支持多种对于文档模型的关联。在建立parent child关系的时候需要注意:child 需要根据parant的id进行路由,parantid 和child的parantid 必须是string。否则回在启动时报错:

OrderDocument

DetailOrderDocument

以上就在 “orders-test” 索引中创建了两个Document。@Id注解对应着Elasticsearch的id。可以系统自动生成,也可以创建文档数据时指定固定的id,但是一定要保证唯一性。 
启动好之后可以通过curl xget来查询索引的结构。结果如下:

另,刚才代码中,通过设置@Document的参数 number_of_shards,number_of_replicas。可以看到创建文档的settings参数:”number_of_shards” : “10”, “number_of_replicas” : “2”。如果不指定参数,则默认分别是 number_of_shards=5,number_of_replicas=1。其他默认参数可以查看public @interface Document源码。

有特殊字符的自生成的id 
用findOne 时会报错,可以用findById 来代替,用query terms精确查找是可以的

Repositories&ElasticsearchTemplate

文档创建好之后,对于文档数据的索引可以继承spring-data-elasticsearch的ElasticsearchRepository。使用CurdRepository接口规范来完成基础的查询,存储,更新操作。如下简单举例了两个查询语句。

如果是比较复杂的查询场景,可以在Repository接口写@Query语句。也可以使用ElasticsearchTemplate来写更灵活的定制化查询:

其他注意事项

  • 如果需要删除parent child映射的索引 
    一般的索引都可以直接使用:

但parant-child 关系mapping的时候,删除之后,如果想重建索引,在启动springboot的时候会出现异常: 
can’t add a _parent field that points to an already existing type, that isn’t already a parent 解决方案是在@Document 属性中设置 createIndex = false(默认是true) ,只在parent document上设置就可以了.这样就可以自由删除index,启动时重建索引。

  • 更新文档的分词 
    官方对于更新映射的说法:mapping-intro https://www./guide/en/elasticsearch/guide/current/mapping-intro.html 
    也就是Elasticsearch不支持直接更新mapping字段的索引方式(不能把一个analyzed字段设置成not_analyzed)。 可以支持添加新的映射字段并且制定分词方式(如 ik),或者只能删除index,重建索引 。 
    如我们示例代码的:

一旦索引创建完成,无法再变更name字段为not_analyzed。所以在一开始设计索引文档时需要谨慎判断。

  • 分页,数据查询多的场景 
    对于数据量很大的文档的索引查询,会出现以下报错:

可以通过以下命令修改索引index_name。这个是index级别的设置,但是不建议更改设置,会增加ES node的内存负担。

虽然可以解决索引数据量大的问题,但是接口的性能会有问题:基本上平均返回时间会+200-300ms。推荐用scroll api: 
Elasticsearch在处理大结果集时可以使用scan和scroll。在Spring Data Elasticsearch中,可以向下面那样使用ElasticsearchTemplate来使用scan和scroll处理大结果集。
search api返回一个单一的结果“页”,而 scroll API 可以被用来检索大量的结果(甚至所有的结果),就像在传统数据库中使用的游标 cursor。 
使用示例如下:

  • 查看节点所有配置信息

结果中还可以看到所有可用插件列表。可以用来检验分词插件等是否安装成功。 
查看mapping信息:

  • 删除child文档索引值,并且添加其他的索引值: 
    可以查看官方文档Indexing parent and child  https://www./guide/en/elasticsearch/guide/current/indexing-parent-child.html  。通过curl删除,查询时都需要指定parentId,因为前面已经介绍过了,child文档是通过parentId进行路由的.如下需要添加routing。

查询时也一样:

同理,新增的时候也需要指定routing

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多