SpringBoot 集成 Elasticsearch

2019-08-08| 发布者: admin| 查看: |

前面在 ubuntu 完成安装 elasticsearch,现在我们springboot将集成elasticsearch。

我们这边直接引入nosql中spring data elasticsearch启动器。

创建项目完成后。

项目结构:

 

pom文件:

 ?xml version="1.0" encoding="utf-8"? 
 project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
 xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" 
 modelversion 4.0.0 /modelversion 
 parent 
 groupid org.springframework.boot /groupid 
 artifactid spring-boot-starter-parent /artifactid 
 version 2.1.6.release /version 
 relativepath/ !-- lookup parent from repository -- 
 /parent 
 groupid com.yatces.elasticsearch /groupid 
 artifactid elasticsearch-demo /artifactid 
 version 0.0.1-snapshot /version 
 name elasticsearch-demo /name 
 description demo project for spring boot /description 
 properties 
 java.version 1.8 /java.version 
 /properties 
 dependencies 
 dependency 
 groupid org.springframework.boot /groupid 
 artifactid spring-boot-starter-data-elasticsearch /artifactid 
 /dependency 
 dependency 
 groupid org.springframework.boot /groupid 
 artifactid spring-boot-starter-test /artifactid 
 scope test /scope 
 /dependency 
 !-- https://mvnrepository.com/artifact/org.projectlombok/lombok -- 
 dependency 
 groupid org.projectlombok /groupid 
 artifactid lombok /artifactid 
 version 1.16.20 /version 
 scope provided /scope 
 /dependency 
 /dependencies 
 build 
 plugins 
 plugin 
 groupid org.springframework.boot /groupid 
 artifactid spring-boot-maven-plugin /artifactid 
 /plugin 
 /plugins 
 /build 
 /project 

本人习惯 yml 文件,将 application.properties 重命名为 application.yml

spring:
 data:
 elasticsearch:
 cluster-name: elasticsearch
 cluster-nodes: 192.168.78.130:9300
@data
@noargsconstructor
@allargsconstructor
@document
public class item {
 long id;
 @field
 string title; //标题
 @field
 string category;// 分类
 @field
 string brand; // 品牌
 @field
 double price; // 价格
 @field
 string images; // 图片地址
}

主要注解:

@document 作用在类,标记实体类为文档对象,一般有四个属性

indexname:对应索引库名称

type:对应在索引库中的类型

shards:分片数量,默认5

replicas:副本数量,默认1

@id 作用在成员变量,标记一个字段作为id主键

@field 作用在成员变量,标记为文档的字段,并指定字段映射属性:

type:字段类型,取值是枚举:fieldtype

index:是否索引,布尔类型,默认是true

store:是否存储,布尔类型,默认是false

analyzer:分词器名称:ik_max_word

用于测试 elasticsearch 的使用,使用 elasticsearchtemplate 操作索引。

@runwith
@springboottest
public class itemtest {
 @autowired
 private elasticsearchtemplate elasticsearchtemplate;
}
@test
public void testcreate{
 // 创建索引,会根据item类的@document注解信息来创建
 elasticsearchtemplate.createindex;
 // 配置映射,会根据item类中的id、field等字段来自动完成映射
 elasticsearchtemplate.putmapping;
}

在 kibana通过 get product/_mapping 查询结果

{
 "product": {
 "mappings": {
 "item": {
 "properties": {
 "brand": {
 "type": "keyword"
 "category": {
 "type": "keyword"
 "images": {
 "type": "keyword",
 "index": false
 "price": {
 "type": "double"
 "title": {
 "type": "text",
 "analyzer": "ik_max_word"
}
@test
public void testdelete{
//elasticsearchtemplate.deleteindex;
// indexname = "product"
elasticsearchtemplate.deleteindex;
}





kibana 再次查询,报404。

{
 "error": {
 "root_cause": [
 "type": "index_not_found_exception",
 "reason": "no such index",
 "resource.type": "index_or_alias",
 "resource.id": "product",
 "index_uuid": "_na_",
 "index": "product"
 "type": "index_not_found_exception",
 "reason": "no such index",
 "resource.type": "index_or_alias",
 "resource.id": "product",
 "index_uuid": "_na_",
 "index": "product"
 "status": 404
}

用于对 document 的操作测试

public interface itemrepository extends elasticsearchrepository item, long {
}

在 itemtest 中注入 itemrepository 

@autowired
private itemrepository itemrepository;

修改和新增是同一个接口,区分的依据就是id,新增用post 请求,修改用put请求。

@test
public void testsavedocument{
 item item = new item;
 itemrepository.save;
}

kibana 通过get product/_search 查询

{
 "took": 1,
 "timed_out": false,
 "_shards": {
 "total": 1,
 "successful": 1,
 "skipped": 0,
 "failed": 0
 "hits": {
 "total": 1,
 "max_score": 1,
 "hits": [
 "_index": "product",
 "_type": "item",
 "_id": "1",
 "_score": 1,
 "_source": {
 "id": 1,
 "title": "小米手机7",
 "category": " 手机",
 "brand": "小米",
 "price": 3499,
 "images": "13123.jpg"
}
@test
public void testsavedocumentlist {
 list item list = new arraylist ;
 list.add);
 list.add);
 list.add);
 list.add);
 list.add);
 // 接收对象集合,实现批量新增
 itemrepository.saveall;
}

kibana 通过get product/_search 再次查询,得到5个doc

在 elasticsearchrepository 继承下来的查询方法

@test
public void testfindbyid{
 optional item optional = itemrepository.findbyid;
 system.out.println);
}

结果

@test
public void testfindall{
 // 查询所有,并根据 price 降序排序
 iterable item items = itemrepository.findall);
 items.foreach;
}

结果

spring data 的提供一个强大功能,是根据方法名称自动实现功能,下述自定义规范:

在itemrepository定义一个方法findbypricebetween,不用写这个方法的实现例如:根据价格区间查询所有 item

/**
 * 根据价格区间查询
 * @param price1
 * @param price2
 * @return
 */






list item findbypricebetween;

在 itemtest 编写测试

@test
public void testfindbypricebetween{
 list item list = this.itemrepository.findbypricebetween;
 list.foreach;
}

结果

repository 的 search 方法,使用 querybuilders 构建查询条件

querybuilders 提供了大量的静态方法,用于生成各种不同类型的查询对象,例如:词条、模糊、通配符等querybuilder对象

public void testquery{
 // 词条查询
 matchquerybuilder querybuilder = querybuilders.matchquery;
 // 执行查询
 iterable item items = this.itemrepository.search;
 items.foreach;
}

结果

@test
public void testnativequery{
 // 构建查询条件
 nativesearchquerybuilder querybuilder = new nativesearchquerybuilder;
 // 添加基本的分词查询
 querybuilder.withquery);
 // 执行搜索,获取结果
 page item items = this.itemrepository.search);
 // 打印总条数
 system.out.println);
 // 打印总页数
 system.out.println);
 items.foreach;
}

结果

nativesearchquerybuilder:spring提供的一个查询条件构建器,帮助构建json格式的请求体。

page item :默认是分页查询,因此返回的是一个分页的结果对象,包含属性:

totalelements:总条数

totalpages:总页数

iterator:迭代器,本身实现了iterator接口,因此可直接迭代得到当前页的数据

利用nativesearchquerybuilder可以方便的实现分页

@test
public void testnativepagequery{
 // 构建查询条件
 nativesearchquerybuilder querybuilder = new nativesearchquerybuilder;
 // 添加基本的分词查询
 querybuilder.withquery);
 // 初始化分页参数
 int page = 0;
 int size = 3;
 // 设置分页参数
 querybuilder.withpageable);
 // 执行搜索,获取结果
 page item items = this.itemrepository.search);
 // 打印总条数
 system.out.println);
 // 打印总页数
 system.out.println);
 // 每页大小
 system.out.println);
 // 当前页
 system.out.println);
 items.foreach;
}

结果:分页是从第0页开始

排序也通用通过nativesearchquerybuilder完成

@test
public void testsortquery{
 // 构建查询条件
 nativesearchquerybuilder querybuilder = new nativesearchquerybuilder;
 // 添加基本的分词查询
 querybuilder.withquery);
 // 排序
 querybuilder.withsort.order);
 // 执行搜索,获取结果
 page item items = this.itemrepository.search);
 // 打印总条数
 system.out.println);
 items.foreach;
}

 结果

按照品牌brand进行分组

@test
public void testbrandagg{
 nativesearchquerybuilder querybuilder = new nativesearchquerybuilder;
 // 不查询任何结果
 querybuilder.withsourcefilter);
 // 1、添加一个新的聚合,聚合类型为terms,聚合名称为brands,聚合字段为brand
 querybuilder.addaggregation.field);
 // 2、查询,需要把结果强转为aggregatedpage类型
 aggregatedpage item aggpage =  this.itemrepository.search);
 // 3、解析
 // 3.1、从结果中取出名为brands的那个聚合,
 // 因为是利用string类型字段来进行的term聚合,所以结果要强转为stringterm类型
 stringterms agg =  aggpage.getaggregation;
 // 3.2、获取桶
 list stringterms.bucket buckets = agg.getbuckets;
 // 3.3、遍历
 for  {
 // 3.4、获取桶中的key,即品牌名称 和 文档数量
 system.out.println + ":" +bucket.getdoccount);
}

结果

 

aggregationbuilders.terms.field 聚合的构建工厂类aggregationbuilders,所有聚合都由这个类来构建

 

aggpage.getaggregation返回的结果都是aggregation类型对象,不过根据字段类型不同,又有不同的子类表示

 

@test
public void testsubavgagg{
 nativesearchquerybuilder querybuilder = new nativesearchquerybuilder;
 // 不查询任何结果
 querybuilder.withsourcefilter);
 // 1、添加一个新的聚合,聚合类型为terms,聚合名称为brands,聚合字段为brand
 querybuilder.addaggregation.field
 .subaggregation.field) // 在品牌聚合桶内进行嵌套聚合,求平均值
 // 2、查询,需要把结果强转为aggregatedpage类型
 aggregatedpage item aggpage =  this.itemrepository.search);
 // 3、解析
 // 3.1、从结果中取出名为brands的那个聚合,
 // 因为是利用string类型字段来进行的term聚合,所以结果要强转为stringterm类型
 stringterms agg =  aggpage.getaggregation;
 // 3.2、获取桶
 list stringterms.bucket buckets = agg.getbuckets;
 // 3.3、遍历
 buckets.foreach bucket.getaggregations.asmap.get;
 system.out.println + "共" + bucket.getdoccount +",平均售价:"+ avg.getvalue );
}

结果