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());
});
*/
}
}总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论