1. 项目部署
1.1 添加依赖
在项目的 pom.xml 中引⼊spring data elasticsearch的启动器。
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-data-elasticsearch</artifactid> </dependency>
1.2 配置application.yml 文件
spring: data: elasticsearch: cluster-name: csdn-elastic cluster-nodes: 127.0.0.1:9301,127.0.0.1:9302,127.0.0.1:9303
需要注意的是,spring data elasticsearch底层使⽤的不是elasticsearch提供的resthighlevelclient,⽽是 transportclient,并不采⽤http协议通信,⽽是访问elasticsearch对外开放的tcp端⼝。
我们在之前集群配置 中,设置的端⼝分别是:9301、9302、9303。
1.3 测试是否注入成功
在test测试⽂件夹下的com.csdn.es包下创建⼀个springdataestests测试类。通过@autowired注解对 elasticsearchtemplate进⾏注⼊,测试对象是否可以获取到。
package com.csdn.es; import org.junit.test; import org.junit.runner.runwith; import org.springframework.beans.factory.annotation.autowired; import org.springframework.boot.test.context.springboottest; import org.springframework.data.elasticsearch.core.elasticsearchtemplate; import org.springframework.test.context.junit4.springrunner; @runwith(springrunner.class) @springboottest public class springdataestests { @autowired private elasticsearchtemplate template; @test public void check() { system.err.println(template); } }
注: 使用 spring data elasticsearch 是springboot 版本不能太高,建议使用 2.1.6.release 版本。如果有 rest client 版本太高也会注入失败,建议使用 6.4.3 。
2. 操作
2.1 索引库操作
2.1.1 实体类注解
1.我们在product实体类上添加下⾯的⼀些注解。
package com.csdn.pojo; import lombok.allargsconstructor; import lombok.data; import lombok.noargsconstructor; import org.springframework.data.annotation.id; import org.springframework.data.elasticsearch.annotations.document; import org.springframework.data.elasticsearch.annotations.field; import org.springframework.data.elasticsearch.annotations.fieldtype; @data @noargsconstructor @allargsconstructor @document(indexname = "csdn", type = "product", shards = 3, replicas = 1) public class product { @id private long id; @field(type = fieldtype.text, analyzer = "ik_max_word") private string title; // 标题 @field(type = fieldtype.keyword) private string category; // 分类 @field(type = fieldtype.keyword) private string brand; // 品牌 @field(type = fieldtype.double) private double price; // 价格 @field(type = fieldtype.keyword, index = false) private string images; // 图⽚地址 }
2.在springdataestests类中定义创建索引的createindex()⽅法。
@test public void createindex() { // 创建索引库,并制定实体类的字节码 template.createindex(product.class); }
2.1.2 创建映射
刚才的注解已经把映射关系也配置上了,所以创建映射只需要这样:
@test public void createmapping() { template.putmapping(product.class); }
2.2 索引数据crud操作
sde的索引数据crud操作并没有封装在elasticsearchtemplate类中,⽽是有⼀个叫做elasticsearchrepository的 接⼝中。
在com.csdn.respository包下⾃定义productrepository接⼝,并继承elasticsearchrespository接⼝。
package com.csdn.respository; import com.yx.pojo.product; import org.springframework.data.elasticsearch.repository.elasticsearchrepository; public interface productrepository extends elasticsearchrepository<product, long> { }
2.2.1 创建索引数据
1.先来看单个创建。在springdataestests类中定义adddocument()⽅法。
@autowired private productrepository productrepository; @test public void adddocument() { product product = new product(1l, "⼩⽶⼿机mix", "⼿机", "⼩⽶", 2899.00, "http://image.yx.com/12479122.jpg"); // 添加索引数据 productrepository.save(product); }
2.再来看批量创建。在springdataestests类中定义adddocuments()⽅法。
@test public void adddocuments() { // 准备⽂档数据 list<product> list = new arraylist<>(); list.add(new product(2l, "坚果⼿机r1", "⼿机", "锤⼦", 3699.00, "http://image.yx.com/12479122.jpg")); list.add(new product(3l, "华为meta20", "⼿机", "华为", 4499.00, "http://image.yx.com/12479122.jpg")); list.add(new product(4l, "⼩⽶pro", "⼿机", "⼩⽶", 4299.00, "http://image.yx.com/12479122.jpg")); list.add(new product(5l, "荣耀v20", "⼿机", "华为", 2799.00, "http://image.yx.com/12479122.jpg")); // 添加索引数据 productrepository.saveall(list); }
2.2.2 查询索引数据
1.根据id查询数据
@test public void findbyid() { optional<product> optional = productrepository.findbyid(1l); product defaultproduct = new product(); defaultproduct.settitle("默认商品数据"); // orelse(t other)⽅法:如果optional对象中封装的泛型为null,则将orelse()⽅法的参数作为返回值 product product = optional.orelse(defaultproduct); system.err.println(product); }
2.查询所有数据
@test public void findall() { iterable<product> list = productrepository.findall(); list.foreach(system.err::println); }
2.2.3 ⾃定义⽅法查询
在productrepository接⼝中定义根据商品的价格区间查询商品数据的findbypricebetween()⽅法。
/** * 根据商品的价格区间查询商品数据 * @param from 开始价格 * @param to 结束价格 * @return 符合条件的商品数据 */ list<product> findbypricebetween(double from, double to);
⽆需写实现,sde会⾃动帮我们实现该⽅法,我们只需要⽤即可。在springdataestests类中定义 findbypricebetween()⽅法。
@test public void findbypricebetween() { list<product> products = productrepository.findbypricebetween(3000d, 5000d); products.foreach(system.err::println); }
2.3 原⽣查询案例
在com.csdn.mapper包下⾃定义搜索结果映射productsearchresultmapper类。
package com.csdn.esclient; import com.google.gson.gson; import org.elasticsearch.action.search.searchresponse; import org.elasticsearch.search.searchhit; import org.elasticsearch.search.searchhits; import org.elasticsearch.common.text.text; import org.elasticsearch.search.fetch.subphase.highlight.highlightfield; import org.springframework.data.domain.pageable; import org.springframework.data.elasticsearch.core.searchresultmapper; import org.springframework.data.elasticsearch.core.aggregation.aggregatedpage; import org.springframework.data.elasticsearch.core.aggregation.impl.aggregatedpageimpl; import java.util.arraylist; import java.util.list; import java.util.map; /** * 1.接口 searchresultmapper 表示用来自定义查询结果映射,将结果按照开发者的配置,进行重组,然后返回客户端 * 2.重写 mapresults */ /** ⾃定义查询结果映射,⽤于处理⾼亮显示 */ public class productsearchresulmapper implements searchresultmapper { @override public <t> aggregatedpage<t> mapresults(searchresponse searchresponse, class<t> aclass, pageable pageable) { // 记录总条数 long totalhits = searchresponse.gethits().gettotalhits(); // 记录列表(泛型) - 构建aggregate使⽤ list<t> list = new arraylist<>(); // 获取搜索结果(真正的的记录) searchhits hits = searchresponse.gethits(); gson gson = new gson(); for (searchhit hit : hits) { if (hits.gethits().length <= 0) { return null; } // 将原本的json对象转换成map对象 map<string, object> map = hit.getsourceasmap(); // 获取⾼亮的字段map map<string, highlightfield> highlightfields = hit.gethighlightfields(); for (map.entry<string, highlightfield> highlightfield : highlightfields.entryset()) { // 获取⾼亮的key string key = highlightfield.getkey(); // 获取⾼亮的value highlightfield value = highlightfield.getvalue(); // 实际fragments[0]就是⾼亮的结果,⽆需遍历拼接 text[] fragments = value.getfragments(); // 因为⾼亮的字段必然存在于map中,就是key值 map.put(key, fragments[0].tostring()); } // 把map转换成对象 t item = gson.fromjson(gson.tojson(map), aclass); list.add(item); } // 返回的是带分⻚的结果 return new aggregatedpageimpl<>(list, pageable, totalhits); } }
java测试类:
package com.csdn.es; import com.qf.esclient.productsearchresulmapper; import com.qf.pojo.product; import org.elasticsearch.index.query.querybuilders; import org.elasticsearch.search.aggregations.aggregationbuilders; import org.elasticsearch.search.fetch.subphase.highlight.highlightbuilder; import org.junit.test; import org.junit.runner.runwith; import org.springframework.beans.factory.annotation.autowired; import org.springframework.boot.test.context.springboottest; import org.springframework.data.domain.pagerequest; import org.springframework.data.domain.sort; import org.springframework.data.elasticsearch.core.elasticsearchtemplate; import org.springframework.data.elasticsearch.core.aggregation.aggregatedpage; import org.springframework.data.elasticsearch.core.query.fetchsourcefilter; import org.springframework.data.elasticsearch.core.query.nativesearchquerybuilder; import org.springframework.test.context.junit4.springrunner; import java.util.list; @springboottest @runwith(springrunner.class) public class springdataestests { @autowired private elasticsearchtemplate template; @test public void test01() { // 1.创建原生查询语句构建 nativesearchquerybuilder builder = new nativesearchquerybuilder(); // 2.通过nativesearchquerybuilder指定过滤器条件 builder.withsourcefilter(new fetchsourcefilter(null,null)); // 3.添加词条搜索条件 builder.withquery(querybuilders.matchquery("title","手机")); // 4.分页操作:当前页其实位置的下标 builder.withpageable(pagerequest.of(0, 2, sort.by(sort.direction.asc, "price"))); // 5.高亮显示 todo highlightbuilder.field field = new highlightbuilder.field("title"); field.pretags("<span style='color:red'>"); field.posttags("</span>"); builder.withhighlightfields(field); // 6.聚合:分组。参数解析:terms()方法指定分组的名称(聚合名称) builder.addaggregation(aggregationbuilders.terms("brandagg").field("brand")); // 7.构建查询的条件,并且执行查询 aggregatedpage<product> packages = template.queryforpage(builder.build(), product.class,new productsearchresulmapper()); long total = packages.gettotalelements(); int totalpages = packages.gettotalpages(); list<product> list = packages.getcontent(); system.out.println("总条数:" + total); system.out.println("总⻚数:" + totalpages); system.out.println("数据:"); list.foreach(system.out::println); // 聚合 /** aggregations aggregations = packages.getaggregations(); // 导包org.elasticsearch.search.aggregations.bucket.terms.terms terms terms = aggregations.get("brandagg"); terms.getbuckets().foreach(b -> { system.err.println("品牌:" + b.getkeyasstring()); system.err.println("count:" + b.getdoccount()); }); */ } }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论