maven依赖
官方客户端 https://www.elastic.co/guide/en/elasticsearch/client/java-rest/6.4/index.html
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.5.0</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.5.0</version>
<exclusions>
<exclusion>
<artifactId>commons-codec</artifactId>
<groupId>commons-codec</groupId>
</exclusion>
<!--此处要排除掉自带的,这个自带的版本低,会报错-->
<exclusion>
<artifactId>elasticsearch</artifactId>
<groupId>org.elasticsearch</groupId>
</exclusion>
</exclusions>
</dependency>
Util类
配置类
package com.crb.ocms.product.domain.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @Project crb-product-domain
* @PackageName com.crb.ocms.product.admin.config
* @ClassName ESConfiguration
* @Author liqiang
* @Date 2019/3/6 5:52 PM
* @Description 用于加载es的相关配置
*/
@ConfigurationProperties(prefix = "esconfig")
@Data
public class ESConfiguration {
/**
* index别名
*/
private String aliasName;
/**
* 索引名字
*/
private String indexName;
/**
* 全量索引的最大处理线程大小
*/
private int threadSize;
/**
* 全量索引并行执行每个线程每次执行数据大小
*/
private int treadDataSize;
/**
* typename
*/
private String typeName;
/**
* ESURL
*/
private String esUrl;
/**
* es ip
*/
private String host;
/**
* es端口
*/
private Integer port;
/***
* 用于标识是否正在处理的rediskey
*/
private String redissKey;
/**
*mappingJson
*/
private String mappingJson;
}
util工具类
package com.crb.ocms.product.service.impl;
import com.crb.ocms.product.domain.config.ESConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.entity.ContentType;
import org.apache.http.nio.entity.NStringEntity;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexResponse;
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.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.support.replication.ReplicationResponse;
import org.elasticsearch.client.*;
import org.elasticsearch.common.CheckedFunction;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.SuggestionBuilder;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.*;
import java.util.regex.Pattern;
/**
* @Project crb-product-service
* @PackageName com.crb.ocms.demo.service.test.impl
* @ClassName ESHLRestUtil
* @Author liqiang
* @Date 2019/2/25 13:45
* @Description es工具类
*/
@Slf4j
@Component
@EnableConfigurationProperties(ESConfiguration.class)
public class ESHLRestUtil {
private RestHighLevelClient client = null;
public RestHighLevelClient getClient() {
return client;
}
public void setClient(RestHighLevelClient client) {
this.client = client;
}
ESConfiguration esConfiguration;
@Autowired
public ESHLRestUtil(ESConfiguration configuration) {
client = new SimpleRestHighLevelClient(RestClient.builder(new HttpHost(configuration.getHost(), configuration.getPort(), "http")));
this.esConfiguration=configuration;
}
public SimpleRestHighLevelClient getSimpleClient(){
return (SimpleRestHighLevelClient)client;
}
/**
*根据indexname获得index名字 支持通配符匹配
* @param indexName
* @return
*/
public String [] getIndexNames(String indexName) {
GetIndexResponse getIndexResponse= null;
try {
getIndexResponse = getIndexInfo(indexName);
} catch (IOException e) {
e.printStackTrace();
}
return getIndexResponse!=null?getIndexResponse.getIndices():null;
}
/**
* 根据index名字获得index信息
* @param indexName
* @return
*/
public GetIndexResponse getIndexInfo(String indexName) throws IOException {
//GetIndexRequest request = new GetIndexRequest().indices(indexName);
// try {
// GetIndexResponse getIndexResponse =client.indices().get(request, RequestOptions.DEFAULT);
// return getIndexResponse;
// } catch (IOException e) {
// e.printStackTrace();
// }
//master_timeout
/**
* 因为现在是api使用6.5 线上是6.24 master_timeout 使用以下方式 替换掉
*/
GetIndexRequest request = new GetIndexRequest().indices(indexName);
String[] indices = request.indices() == null ? Strings.EMPTY_ARRAY : request.indices();
String endpoint =indexName;
Request httpequest = new Request("GET", endpoint);
httpequest.addParameter("ignore_unavailable", "false");
httpequest.addParameter("expand_wildcards", "open");
httpequest.addParameter("allow_no_indices", "true");
org.apache.http.HttpEntity entity = new NStringEntity("", ContentType.APPLICATION_JSON);
httpequest.setEntity(entity);
Response httpResponse= getClient().getLowLevelClient().performRequest(httpequest);
GetIndexResponse getIndexResponse=getSimpleClient().parseGetIndexRespons(httpResponse);
return getIndexResponse;
}
/**
* 获得最大index名字
* @param names indexName_number 格式
* @return
*/
public Integer getMaxIndexNumber(String []names) {
if(names==null||names.length<=0){
return null;
}
List<Integer> indexNumber=new ArrayList<Integer>();
for (String name:
names) {
String[] arrs=name.split("_");
if(arrs.length<=1){
continue;
}
indexNumber.add(Integer.valueOf(arrs[1]));
}
indexNumber.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
return CollectionUtils.isEmpty(indexNumber)?null:indexNumber.get(0);
}
/**
* 验证索引是否存在
*
* @param index 索引名称
* @return
* @throws Exception
*/
public boolean indexExists(String index) throws Exception {
GetIndexRequest request = new GetIndexRequest();
request.indices(index);
boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
return exists;
}
/**
* 创建index
*
* @param index
* @param indexType
* @param properties 结构: {name:{type:text}} {age:{type:integer}}
* @return
* @throws Exception
*/
public boolean indexCreate(String index, String indexType,
Map properties) throws Exception {
if (indexExists(index)) {
return true;
}
CreateIndexRequest request = new CreateIndexRequest(index);
request.settings(Settings.builder().put("index.number_of_shards", 3)
.put("index.number_of_replicas", 2));
Map jsonMap = new HashMap<>();
Map mapping = new HashMap<>();
mapping.put("properties", properties);
jsonMap.put(indexType, mapping);
request.mapping(indexType, jsonMap);
CreateIndexResponse createIndexResponse = client.indices().create(
request,RequestOptions.DEFAULT);
boolean acknowledged = createIndexResponse.isAcknowledged();
return acknowledged;
}
/**
* 删除指定索引
* @param indexName
* @return
* @throws IOException
*/
public boolean deleteIndex(String indexName) throws IOException {
DeleteIndexRequest request = new DeleteIndexRequest(indexName);
AcknowledgedResponse deleteIndexResponse = client.indices().delete(request, RequestOptions.DEFAULT);
return deleteIndexResponse.isAcknowledged();
}
/**
* 创建索引
* @param index 索引名字
* @param settiongs settiongs
* @return
* @throws Exception
* @author lqiang
*/
public boolean indexCreate(String index, String settiongs
) throws Exception {
if (indexExists(index)) {
return true;
}
CreateIndexRequest request = new CreateIndexRequest(index);
// request.settings(Settings.builder().put("index.number_of_shards", 3)
// .put("index.number_of_replicas", 2));
request.source(settiongs, XContentType.JSON);
CreateIndexResponse createIndexResponse = client.indices().create(
request,RequestOptions.DEFAULT);
boolean acknowledged = createIndexResponse.isAcknowledged();
return acknowledged;
}
/**
* 创建更新文档
*
* @param index
* @param indexType
* @param documentId
* @param josonStr
* @return
* @throws Exception
*/
public boolean documentCreate(String index, String indexType,
String documentId, String josonStr) throws Exception {
IndexRequest request = new IndexRequest(index, indexType, documentId);
request.source(josonStr, XContentType.JSON);
IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT);
if (indexResponse.getResult() == DocWriteResponse.Result.CREATED
|| indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
return true;
}
ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo();
if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
return true;
}
if (shardInfo.getFailed() > 0) {
for (ReplicationResponse.ShardInfo.Failure failure : shardInfo
.getFailures()) {
throw new Exception(failure.reason());
}
}
return false;
}
/**
* 创建更新文档
*
* @param index
* @param indexType
* @param documentId
* @param map
* @return
* @throws Exception
*/
public boolean documentCreate(String index, String indexType,
String documentId, Map map) throws Exception {
IndexRequest request = new IndexRequest(index, indexType, documentId);
request.source(map);
IndexResponse indexResponse = client.index(request,RequestOptions.DEFAULT);
if (indexResponse.getResult() == DocWriteResponse.Result.CREATED
|| indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
return true;
}
ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo();
if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
return true;
}
if (shardInfo.getFailed() > 0) {
for (ReplicationResponse.ShardInfo.Failure failure : shardInfo
.getFailures()) {
throw new Exception(failure.reason());
}
}
return false;
}
/**
* 批量创建更新文档
*
* @param index
* @param indexType
* @param list 建索引时传入_id作为docuemntId
* @return
* @throws Exception
*/
public boolean documentCreateBulk(String index, String indexType,
List<Map<String, Object>> list) throws Exception {
if (list.size() > 0) {
BulkRequest bulkRequest = new BulkRequest();
for (Map map : list) {
IndexRequest indexRequest;
Object idObj = map.get("_id");
if (idObj != null && StringUtils.isNotBlank(idObj.toString())) {
map.remove("_id");
String documentId = idObj.toString();
indexRequest = new IndexRequest(index, indexType, documentId);
} else {
indexRequest = new IndexRequest(index, indexType);
}
indexRequest.source(map);
bulkRequest.add(indexRequest);
}
BulkResponse bulkResponse = client.bulk(bulkRequest,RequestOptions.DEFAULT);
if (bulkResponse.hasFailures()) {
System.out.println("索引异常信息:" + bulkResponse.buildFailureMessage());
return false;
}
}
return true;
}
/**
* 创建更新文档
*
* @param index
* @param indexType
* @param documentId
* @param routing
* @param map
* @return
* @throws Exception
*/
public boolean documentCreate(String index, String indexType,
String documentId, String routing, Map map) throws Exception {
IndexRequest request = new IndexRequest(index, indexType, documentId);
request.routing(routing);
request.source(map);
IndexResponse indexResponse = client.index(request,RequestOptions.DEFAULT);
if (indexResponse.getResult() == DocWriteResponse.Result.CREATED
|| indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
return true;
}
ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo();
if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
return true;
}
if (shardInfo.getFailed() > 0) {
for (ReplicationResponse.ShardInfo.Failure failure : shardInfo
.getFailures()) {
throw new Exception(failure.reason());
}
}
return false;
}
/**
* 创建索引
*
* @param index
* @param indexType
* @param josonStr
* @return
* @throws Exception
*/
public String documentCreate(String index, String indexType, String josonStr)
throws Exception {
IndexRequest request = new IndexRequest(index, indexType);
request.source(josonStr, XContentType.JSON);
IndexResponse indexResponse = client.index(request,RequestOptions.DEFAULT);
String id = indexResponse.getId();
if (indexResponse.getResult() == DocWriteResponse.Result.CREATED
|| indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
return id;
}
ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo();
if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
return id;
}
if (shardInfo.getFailed() > 0) {
for (ReplicationResponse.ShardInfo.Failure failure : shardInfo
.getFailures()) {
throw new Exception(failure.reason());
}
}
return null;
}
/**
* 创建索引
*
* @param index
* @param indexType
* @param map
* @return
* @throws Exception
*/
public String documentCreate(String index, String indexType,
Map map) throws Exception {
IndexRequest request = new IndexRequest(index, indexType);
request.source(map);
IndexResponse indexResponse = client.index(request,RequestOptions.DEFAULT);
String id = indexResponse.getId();
if (indexResponse.getResult() == DocWriteResponse.Result.CREATED
|| indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
return id;
}
ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo();
if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
return id;
}
if (shardInfo.getFailed() > 0) {
for (ReplicationResponse.ShardInfo.Failure failure : shardInfo
.getFailures()) {
throw new Exception(failure.reason());
}
}
return null;
}
public boolean documentDelete(String index, String indexType,
String documentId) throws Exception {
DeleteRequest request = new DeleteRequest(index, indexType, documentId);
DeleteResponse deleteResponse = client.delete(request,RequestOptions.DEFAULT);
if (deleteResponse.getResult() == DocWriteResponse.Result.NOT_FOUND) {
return true;
}
ReplicationResponse.ShardInfo shardInfo = deleteResponse.getShardInfo();
if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
return true;
}
if (shardInfo.getFailed() > 0) {
for (ReplicationResponse.ShardInfo.Failure failure : shardInfo
.getFailures()) {
throw new Exception(failure.reason());
}
}
return false;
}
/**
* 为指定index指定别名
* @param indexName index名字
* @param aliasesName 别名名字
* @return
*/
public boolean aliases(String indexName,String aliasesName){
IndicesAliasesRequest request=new IndicesAliasesRequest();
IndicesAliasesRequest.AliasActions aliasAction =
new IndicesAliasesRequest.AliasActions(IndicesAliasesRequest.AliasActions.Type.ADD)
.index(indexName)
.alias(aliasesName);
request.addAliasAction(aliasAction);
try {
AcknowledgedResponse indicesAliasesResponse =
getClient().indices().updateAliases(request, RequestOptions.DEFAULT);
return indicesAliasesResponse.isAcknowledged();
} catch (IOException e) {
log.info("指定别名失败");
return false;
}
}
/**
* 指定别名 并删除oldIndex的别名
* @param oldindex
* @param newIndex
* @param aliasesName
* @return
*/
public boolean aliases(String oldindex, String newIndex,String aliasesName) {
IndicesAliasesRequest request=new IndicesAliasesRequest();
//旧的删除
IndicesAliasesRequest.AliasActions aliasAction =
new IndicesAliasesRequest.AliasActions(IndicesAliasesRequest.AliasActions.Type.REMOVE)
.index(oldindex)
.alias(aliasesName);
request.addAliasAction(aliasAction);
//新的绑定
aliasAction =
new IndicesAliasesRequest.AliasActions(IndicesAliasesRequest.AliasActions.Type.ADD)
.index(newIndex)
.alias(aliasesName);
request.addAliasAction(aliasAction);
try {
AcknowledgedResponse indicesAliasesResponse =
getClient().indices().updateAliases(request, RequestOptions.DEFAULT);
return indicesAliasesResponse.isAcknowledged();
} catch (IOException e) {
return false;
}
}
/**
* 根据id获得文档信息
* @param index indexName
* @param type typeName
* @param id id
* @return
* @throws IOException
*/
public GetResponse getDoucmentById(String index, String type, String id) throws IOException {
GetRequest getRequest = new GetRequest(
index,//索引
type,//类型
id);//文档ID
GetResponse getResponse = client.get(getRequest,RequestOptions.DEFAULT);
return getResponse;
}
/**
* 简单的单表根据条件进行查询
*
* @param index index
* @param type type
* @param parameters 参数
* @return
*/
public List<String> queryByMatch(String index, String type, Map<String, String> parameters) {
List<String> jsons=new ArrayList<String>();
try {
SearchRequest searchRequest=new SearchRequest();
BoolQueryBuilder booleanQueryBuilder= QueryBuilders.boolQuery();
SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
for (String key :
parameters.keySet()) {
booleanQueryBuilder.must().add(QueryBuilders.termQuery(key,parameters.get(key)));
}
searchSourceBuilder.query(booleanQueryBuilder);
searchRequest.source(searchSourceBuilder);
SearchResponse response = client.search(searchRequest,RequestOptions.DEFAULT);
if(response.getHits().getHits()!=null){
for (SearchHit searchHit:
response.getHits().getHits() ) {
jsons.add(searchHit.getSourceAsString());
}
}
} catch (IOException e) {
e.printStackTrace();
}
return jsons;
}
/**
* 只包含字母
*
* @return 验证成功返回true,验证失败返回false
*/
public static boolean checkLetter(String cardNum) {
String regex = "^[A-Za-z]+$";
return Pattern.matches(regex, cardNum);
}
/**
* 验证中文
*
* @param chinese 中文字符
* @return 验证成功返回true,验证失败返回false
*/
public static boolean checkChinese(String chinese) {
String regex = "^[\u4E00-\u9FA5]+$";
return Pattern.matches(regex, chinese);
}
/**
* Description:提示词,支持中文、拼音、首字母等
* <p>
* 1、检测搜索词是中文还是拼音
* 2、若是中文,直接按照name字段提示
* 3、若是拼音(拼音+汉字),先按照name.keyword_pinyin获取,若是无结果按照首字母name.keyword_first_py获取
* @param index
* @param type
* @param field 提示字段名字
* @param text 文本
* @return
* @author liqiang
*/
public Set<String> getSuggestWord(String index, String type, String field, String text) throws IOException {
String postField=field;
if (checkLetter(text)) {
postField = field + ".keyword_pinyin";
} else if (checkChinese(text)) {
postField = field;
} else {
postField = field + ".keyword_pinyin";
}
Set<String> suggestTexts= postSuggestWord(index,type,postField,text);
if(org.springframework.util.CollectionUtils.isEmpty(suggestTexts)){
return postSuggestWord(index,type,field+".keyword_first_py",text);
}
return suggestTexts;
}
/**
* Description:提示词,支持中文、拼音、首字母等
* @param index
* @param type
* @param field 提示字段名字
* @param text 文本
* @return
* @author liqiang
*/
private Set<String> postSuggestWord(String index, String type, String field, String text) throws IOException {
// 1、创建search请求
SearchRequest searchRequest = new SearchRequest(index);
searchRequest.types(type);
// 2、用SearchSourceBuilder来构造查询请求体 ,请仔细查看它的方法,构造各种查询的方法都在这。
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.fetchSource(false);//不返回_source数据
sourceBuilder.size(0);//忽略hits
//做查询建议
//词项建议
SuggestionBuilder termSuggestionBuilder =
SuggestBuilders.completionSuggestion(field).text(text);
SuggestBuilder suggestBuilder = new SuggestBuilder();
suggestBuilder.addSuggestion("suggest_productName", termSuggestionBuilder);
sourceBuilder.suggest(suggestBuilder);
searchRequest.source(sourceBuilder);
Set<String> suggestTextList = new HashSet<String>();
//3、发送请求
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
//4、处理响应
//搜索结果状态信息
if (RestStatus.OK.equals(searchResponse.status())) {
// 获取建议结果
Suggest suggest = searchResponse.getSuggest();
CompletionSuggestion termSuggestion = suggest.getSuggestion("suggest_productName");
for (CompletionSuggestion.Entry entry : termSuggestion.getEntries()) {
for (CompletionSuggestion.Entry.Option option : entry) {
suggestTextList.add(option.getText().string());
}
}
}
return suggestTextList;
}
/**
* @Project demo
* @PackageName com.crb.ocms.product.service.impl
* @ClassName SimpleRestHighLevelClient
* @Author qiang.li
* @Date 2019/4/2 10:45 AM
* @Description es版本降级导致的高级api会生成部分属性 低版本不能识别 将解析结果的方法暴露在外面
*/
public class SimpleRestHighLevelClient extends RestHighLevelClient {
public SimpleRestHighLevelClient(RestClientBuilder restClientBuilder) {
super(restClientBuilder);
}
/**
* 父类解析的解析响应内容是受保护的 所以定义一个继承
* 解决版本不一致的 自定义请求 解析
* @param response
* @param entityParser
* @param <Req>
* @param <Resp>
* @return
* @throws IOException
*/
public <Req extends Validatable, Resp> Resp parseEntity(Response response,CheckedFunction<XContentParser, Resp, IOException> entityParser)throws IOException {
return this.parseEntity(response.getEntity(),entityParser);
}
/**
* 解析获得idnex的响应
* @param response
* @return
* @throws IOException
*/
public GetIndexResponse parseGetIndexRespons(Response response) throws IOException {
return parseEntity(response,GetIndexResponse::fromXContent);
}
/**
* 解析查询响应
* @param response
* @return
* @throws IOException
*/
public SearchResponse parseSearchResponse(Response response) throws IOException {
return parseEntity(response,SearchResponse::fromXContent);
}
/**
* 解析索引迁移响应
* @param response
* @return
* @throws IOException
*/
public BulkByScrollResponse parseBulkByScrollResponse(Response response) throws IOException {
return parseEntity(response,BulkByScrollResponse::fromXContent);
}
}
}
封装的处理器
工作原理
将指定条件的数据迁移到新索引,然后再新索引上面进行导入(多线程并行导入),导入完毕删除老索引和别名 然后为新索引绑定别名 实现不停机更新