基于es7.10.x版本
一、前提知识
常见的两种方式:spring boot提供的api 和 es 官方提供的api
-
es官方:
resthighlevelclient:
适用于复杂、更细粒度控制的elasticsearch 操作 -
spring boot:
elasticsearchresttemplate:比 resthighlevelclient 抽象更高,更接近于 spring data 的风格,当你想利用 spring data 的特性(如查询方法、分页等)与 elasticsearch 交互时,这是一个很好的选择,但有些复杂查询无法完成。
elasticsearchrepository:抽象级别最高,隐藏了与 elasticsearch 交互的底层细节,并提供了基于方法的查询功能,能够快速实现 crud 操作。
建议使用resthighlevelclient
原因:
版本:elasticsearchresttemplate本身与spring-boot-starter-data-elasticsearch紧密依赖。如果想升级elasticsearchresttemplate,那就必须连带升级项目的springboot版本,这个风险就比较高了,一般项目的springboot版本不会轻易升级
灵活度:比较灵活,可以直接使用es的dsl语法,实现复杂查询,同时没有与其他部件绑定,所以版本可以自由选择。,由于elasticsearchresttemplate是spring-boot-starter-data-elasticsearch封装的工具类,虽然使用上稍微方便一些,但是失去了灵活性,出现问题时也不易排查。
二、环境搭建
1、es 官方
resthighlevelclient 方式
<dependency>
<groupid>org.elasticsearch</groupid>
<artifactid>elasticsearch</artifactid>
<version>7.10.0</version>
</dependency>
<dependency>
<groupid>org.elasticsearch.client</groupid>
<artifactid>elasticsearch-rest-client</artifactid>
<version>7.10.0</version>
</dependency>
<dependency>
<groupid>org.elasticsearch.client</groupid>
<artifactid>elasticsearch-rest-high-level-client</artifactid>
<version>7.10.0</version>
</dependency>
spring:
elasticsearch:
uris: http://172.31.97.4:9280
username: xxxx
password: xxxx
2、springdata
elasticsearchresttemplate+elasticsearchrepository 方式
首先springdata操作es必须要将版本号和es的版本号对应上,否则会报错(倒不用完全一一对应,但版本号最好不要相差太多)。springdata引入的版本号由springboot的版本号决定,对应关系如下:
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-data-elasticsearch</artifactid>
</dependency>
spring:
elasticsearch:
uris: http://172.31.97.4:9280
username: xxxx
password: xxxx
二、api方法
1、es 官方
工工具类
package com.wang.service;
import cn.hutool.core.collection.collutil;
import cn.hutool.core.util.strutil;
import cn.hutool.json.jsonobject;
import cn.hutool.json.jsonutil;
import lombok.extern.slf4j.slf4j;
import org.elasticsearch.action.bulk.bulkrequest;
import org.elasticsearch.action.bulk.bulkresponse;
import org.elasticsearch.action.delete.deleterequest;
import org.elasticsearch.action.delete.deleteresponse;
import org.elasticsearch.action.get.getrequest;
import org.elasticsearch.action.get.getresponse;
import org.elasticsearch.action.index.indexrequest;
import org.elasticsearch.action.search.searchrequest;
import org.elasticsearch.action.search.searchresponse;
import org.elasticsearch.action.update.updaterequest;
import org.elasticsearch.action.update.updateresponse;
import org.elasticsearch.client.requestoptions;
import org.elasticsearch.client.resthighlevelclient;
import org.elasticsearch.client.core.countrequest;
import org.elasticsearch.client.core.countresponse;
import org.elasticsearch.client.indices.createindexrequest;
import org.elasticsearch.client.indices.getindexrequest;
import org.elasticsearch.common.text.text;
import org.elasticsearch.common.unit.timevalue;
import org.elasticsearch.common.xcontent.xcontentbuilder;
import org.elasticsearch.common.xcontent.xcontenttype;
import org.elasticsearch.common.xcontent.json.jsonxcontent;
import org.elasticsearch.index.query.abstractquerybuilder;
import org.elasticsearch.rest.reststatus;
import org.elasticsearch.search.searchhit;
import org.elasticsearch.search.searchhits;
import org.elasticsearch.search.builder.searchsourcebuilder;
import org.elasticsearch.search.fetch.subphase.highlight.highlightbuilder;
import org.elasticsearch.search.fetch.subphase.highlight.highlightfield;
import org.elasticsearch.search.sort.sortorder;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.component;
import java.io.ioexception;
import java.util.arraylist;
import java.util.hashmap;
import java.util.list;
import java.util.map;
/**
* @author spider man
* @date 2024-05-23 15:15
*/
@component
@slf4j
public class esutils {
@autowired
resthighlevelclient eshighlevelclient;
/**
* 获取总条数
*
* @param indexname
* @return
* @throws ioexception
*/
public long gettotalnum(string indexname) throws ioexception {
countrequest countrequest = new countrequest(indexname);
// 如果需要,你可以在这里添加查询条件
// countrequest.query(querybuilders.matchquery("field_name", "value"));
countresponse countresponse = eshighlevelclient.count(countrequest, requestoptions.default);
return countresponse.getcount();
}
/**
* 获取总页数
*
* @param totalnum
* @param limit
* @return
*/
public int gettotalpage(long totalnum, int limit) {
//总页数
return (int) math.ceil((double) totalnum / limit);
}
/**
* 批量插入数据
*
* @param indexname
* @param list
* @return boolean
*/
public boolean multiadddoc(string indexname, list<jsonobject> list) {
try {
bulkrequest bulkrequest = new bulkrequest();
list.foreach(doc -> {
string source = jsonutil.tojsonstr(doc);
indexrequest indexrequest = new indexrequest(indexname);
indexrequest.source(source, xcontenttype.json);
bulkrequest.add(indexrequest);
});
bulkresponse bulkresponse = eshighlevelclient.bulk(bulkrequest, requestoptions.default);
if (bulkresponse.hasfailures()){
log.error("批量插入失败,第一条错误原因为 {}",bulkresponse.getitems()[0].getfailuremessage());
}else {
log.info("批量插入成功,向索引 {} 中批量插入 {} 条数据", indexname, list.size());
}
return !bulkresponse.hasfailures();
} catch (exception e) {
e.printstacktrace();
}
return false;
}
/**
* 根据id更新文档,全部字段更新
*
* @param indexname
* @param docid
* @param jsonobject
* @return boolean
*/
public boolean updatedocallfiled(string indexname, string docid, jsonobject jsonobject) {
try {
updaterequest updaterequest = new updaterequest(indexname, docid).doc(jsonutil.tojsonstr(jsonobject), xcontenttype.json);
updateresponse updateresponse = eshighlevelclient.update(updaterequest, requestoptions.default);
int total = updateresponse.getshardinfo().gettotal();
log.info("更新文档的影响数量为{}", total);
return total > 0;
} catch (exception e) {
e.printstacktrace();
}
return false;
}
/**
* 局部更新
*
* @param indexname
* @param map key为文档的id,map为所要更新字段的字段名称和值
* @return
* @throws ioexception
*/
public boolean updatedocsomefiled(string indexname, map<string,map<string, object>> map) throws ioexception {
if (collutil.isempty(map)) {
log.info("局部更新数据不能为空");
return false;
}
bulkrequest bulkrequest = new bulkrequest();
map.foreach((docid, value) -> {
updaterequest updaterequest = new updaterequest(indexname, docid);
updaterequest.doc(value);
bulkrequest.add(updaterequest);
});
if (collutil.isnotempty(bulkrequest.requests())) {
bulkresponse bulkresponse = eshighlevelclient.bulk(bulkrequest, requestoptions.default);
if (bulkresponse.hasfailures()) {
log.error("更新失败====》" + bulkresponse.buildfailuremessage());
return false;
}
return true;
} else {
return false;
}
}
/**
* 例如:
* termquerybuilder termquerybuilder = querybuilders.termquery("ethnic_code.keyword", "汉族");
* map<string, object> map = esutils.conditionsearchbyselfquery(index, 1, 60, "pat_name",
* termquerybuilder, "age_year", sortorder.asc, null, true);
*
*
* 条件搜索分页
*
* @param indexname 索引库
* @param pagenum 起始页
* @param pagesize 每页大小
* @param highname 高亮字段
* @param abstractquerybuilder 搜索条件
* @param sortname 排序字段
* @param sortorder 排序类型
* @param includes 显示的字段
* @param isshowdocumentid 是否显示文档id
* @return
* @throws ioexception
*/
public map<string, object> conditionsearchbyselfquery(string indexname, integer pagenum, integer pagesize, string highname, abstractquerybuilder abstractquerybuilder, string sortname, sortorder sortorder, string[] includes, boolean isshowdocumentid) throws ioexception {
searchrequest searchrequest = new searchrequest(indexname);
//构造搜索条件
searchsourcebuilder sourcebuilder = new searchsourcebuilder();
sourcebuilder.fetchsource(includes, null);
if (sortname != null && sortorder != null) {
sourcebuilder.sort(sortname, sortorder);
}
sourcebuilder.query(abstractquerybuilder);
//高亮处理
if (!strutil.isempty(highname)) {
buildhighlight(sourcebuilder, highname);
}
//分页处理
if (pagenum != null && pagesize != null) {
sourcebuilder.from(pagesize * (pagenum - 1));
sourcebuilder.size(pagesize);
}
//超时设置
sourcebuilder.timeout(timevalue.timevalueseconds(60));
system.out.println("dsl语句为:\n"+sourcebuilder);
searchrequest.source(sourcebuilder);
//执行搜索
searchresponse searchresponse = eshighlevelclient.search(searchrequest, requestoptions.default);
searchhits searchhits = searchresponse.gethits();
list<jsonobject> resultlist = new arraylist<>();
for (searchhit hit : searchhits) {
//原始查询结果数据
map<string, object> sourceasmap = hit.getsourceasmap();
if (isshowdocumentid) {
sourceasmap.put("_id", hit.getid());
}
//高亮处理
if (!strutil.isempty(highname)) {
map<string, highlightfield> highlightfields = hit.gethighlightfields();
highlightfield highlightfield = highlightfields.get(highname);
if (highlightfield != null) {
text[] fragments = highlightfield.fragments();
stringbuilder value = new stringbuilder();
for (text text : fragments) {
value.append(text);
}
sourceasmap.put(highname, value.tostring());
}
}
jsonobject jsonobject = jsonutil.parseobj(jsonutil.tojsonstr(sourceasmap));
resultlist.add(jsonobject);
}
long total = searchhits.gettotalhits().value;
map<string, object> pagemap = new hashmap<>();
if (pagenum != null && pagesize != null) {
//当前页
pagemap.put("pagenum", pagenum);
//每页显示条数
pagemap.put("pagesize", pagesize);
//总页数
pagemap.put("totalpage", total == 0 ? 0 : (int) (total % pagesize == 0 ? total / pagesize : (total / pagesize) + 1));
}
//总条数
pagemap.put("totalnum", total);
//数据
pagemap.put("data", resultlist);
return pagemap;
}
/**
* 构建高亮字段
*
* @param sourcebuilder
* @param highname
*/
private void buildhighlight(searchsourcebuilder sourcebuilder, string highname) {
highlightbuilder highlightbuilder = new highlightbuilder();
//设置高亮字段
highlightbuilder.field(highname);
//多个高亮显示
highlightbuilder.requirefieldmatch(false);
//高亮标签前缀
highlightbuilder.pretags("<span style='color:red'>");
//高亮标签后缀
highlightbuilder.posttags("</span>");
sourcebuilder.highlighter(highlightbuilder);
}
/**
* 根据id删除
*
* @param indexname
* @param id
*/
public void deletebyid(string indexname, string id) {
deleterequest deleterequest = new deleterequest(indexname).id(id);
try {
deleteresponse deleteresponse = eshighlevelclient.delete(deleterequest, requestoptions.default);
if (deleteresponse.status().getstatus() != reststatus.ok.getstatus()) {
log.error(">>>> 删除id={}数据失败,返回状态码={} <<<<", id, deleteresponse.status().getstatus());
}
} catch (ioexception e) {
log.error(">>>> 删除数据发生异常,id={},异常信息={} <<<<", id, e.getmessage());
}
}
/**
* 根据id查询
*
* @param indexname
* @param id
* @return
*/
public map<string, object> querybyid(string indexname, string id) {
getrequest getrequest = new getrequest(indexname).id(id);
map<string, object> map = null;
try {
getresponse getresponse = eshighlevelclient.get(getrequest, requestoptions.default);
map = getresponse.getsource();
} catch (ioexception e) {
e.printstacktrace();
}
return map;
}
/**
* 判断索引是否存在
*
* @param indexname 索引名称
* @return
* @throws ioexception
*/
public boolean indexisexists(string indexname) throws ioexception {
getindexrequest getindexrequest = new getindexrequest(indexname);
return eshighlevelclient.indices().exists(getindexrequest, requestoptions.default);
}
public boolean createindex(string indexname, map<string, object> propertymap) throws ioexception {
boolean flag = false;
if (!indexisexists(indexname)) {
try {
createindexrequest index = new createindexrequest("index_name");
map<string, object> properties = new hashmap<>();
map<string, object> propertie = new hashmap<>();
propertie.put("type", "text");
propertie.put("index", true);
propertie.put("analyzer", "ik_max_word");
properties.put("field_name", propertie);
xcontentbuilder builder = jsonxcontent.contentbuilder();
builder.startobject()
.startobject("mappings")
.startobject("index_name")
.field("properties", properties)
.endobject()
.endobject()
.startobject("settings")
.field("number_of_shards", 3)
.field("number_of_replicas", 1)
.endobject()
.endobject();
index.source(builder);
eshighlevelclient.indices().create(index, requestoptions.default);
flag = true;
} catch (ioexception e) {
e.printstacktrace();
throw new runtimeexception("创建索引和映射关系失败");
}
}
return flag;
}
}
发表评论