项目依赖
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>5.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.24</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.7</version>
</dependency>
配置ES集群节点
public class EsConfig {
/**
* Es集群名称
*/
public static final String ES_CLUSTER_NAME = SystemConfig.get("es.cluster.name");
/**
* 已经解析的端口和地址
*/
public static List<URL> es_cluster_urls = loadUrls();
public static List<URL> loadUrls() {
String urls = SystemConfig.get("es.cluster.url");
if (!StringUtils.hasLength(urls)) {
throw new IllegalStateException("Es cluster urls must not be empty.");
}
List<URL> ups = new LinkedList<>();
String[] urlArray = urls.split(",");
for (String up : urlArray) {
String url = up.split(":")[0];
String port = up.split(":")[1];
ups.add(new URL(url, Integer.parseInt(port)));
}
return ups;
}
public static class URL {
private String url;
private int port;
public URL() {
}
public URL(String url, int port) {
this.port = port;
this.url = url;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}
}
ES客户端单例创建
public class ESClient {
private static Logger log = LoggerFactory.getLogger(ESClient.class);
private static ESClient instance = new ESClient();
private static TransportClient client;
private ESClient() {
newTransportClient();
}
public static ESClient instance() {
return instance;
}
public TransportClient getTransportClient() {
// client创建完成后,如果es连接失败将会自动重连
if (client == null/* || client.connectedNodes().isEmpty()*/) {
newTransportClient();
}
return client;
}
private void newTransportClient() {
Settings settings = Settings.EMPTY;
if (StringUtils.hasLength(EsConfig.ES_CLUSTER_NAME))
settings = Settings.builder().put("cluster.name", EsConfig.ES_CLUSTER_NAME).build();
client = new PreBuiltTransportClient(settings);
if (EsConfig.es_cluster_urls.size() == 0) {
throw new NoNodeAvailableException("There is no available node be defined, please check you cluster url configuration.");
}
EsConfig.es_cluster_urls.forEach(url -> {
try {
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(url.getUrl()), url.getPort()));
} catch (UnknownHostException e) {
log.error("Es cluster configuration throw UnkownHostException : ", e);
}
});
}
public void closeClient() {
instance().getTransportClient().close();
}
}
ES客户端的增删改查接口
public interface ESService {
/**
* 创建索引。
* <p>
* 路由如果为空,则不设置路由。
*
* @param index 索引名称
* @param type 类型名称
* @param id id
* @param jsonContent 索引内容
* @param parent 关联父级的字段
* @param routing 路由
* @return 索引结果对象
*/
IndexResponse index(String index, String type, String id, String jsonContent, String parent, String routing);
/**
* 创建索引。
*
* @param index 索引名称
* @param type 类型名称
* @param id id
* @param jsonContent 索引内容
* @return 索引结果对象
*/
IndexResponse index(String index, String type, String id, String jsonContent);
/**
* 批量创建索引。
*
* @param index 索引名称,不能为空
* @param type 索引类型,不能为空
* @param ids 索引id列表,必须与索引内容列表一一对应
* @param contents 索引内容列表,必须与索引id列表一一对应
* @param parent 父级ID
* @param routing 路由
* @return 批量操作结果
*/
BulkResponse bulkIndex(String index, String type, List<String> ids, List<String> contents, String parent, String routing);
/**
* 根据id查询。
*
* @param index 索引名称
* @param type 类型名称
* @param id id
* @return 结果对象
*/
GetResponse get(String index, String type, String id);
/**
* 根据id查询,如果<code>routing</code>为null,则不设置路由。
*
* @param index 索引名称
* @param type 类型名称
* @param id id
* @param parent 父级
* @param routing 路由
* @return 结果对象
*/
GetResponse get(String index, String type, String id, String parent, String routing);
/**
* 批量查询。
*
* @param index 索引名称
* @param type 类型名称
* @param ids 批量查询的id数组
* @return 结果对象
*/
MultiGetResponse multiGet(String index, String type, String[] ids);
/**
* 更新。
*
* @param index 索引名称
* @param type 类型名称
* @param id id
* @param jsonContent 更新内容
* @param create 不存在时是否创建,true - 创建, false - 不创建(默认值)
* @return 结果对象
* @throws ExecutionException
* @throws InterruptedException
*/
UpdateResponse update(String index, String type, String id, String jsonContent, boolean create) throws ExecutionException, InterruptedException;
/**
* 更新。
* <p>
* 如果<code>routing</code>为null,则不设置路由。
*
* @param index 索引名称
* @param type 类型名称
* @param id id
* @param jsonContent 更新内容
* @param parent 父级
* @param routing 路由
* @param create 不存在时是否创建,true - 创建, false - 不创建(默认值)
* @return 结果对象
* @throws ExecutionException
* @throws InterruptedException
*/
UpdateResponse update(String index, String type, String id, String jsonContent, String parent, String routing, boolean create) throws ExecutionException, InterruptedException;
/**
* 批量更新。
* <p>
* 如果<code>routing</code>为null,则不设置路由。
* <p>
* 如果文档不存在,会自动创建文档。如果不希望创建文档,可以参见带create参数的bulkUpdate方法。
*
* @param index 索引名称
* @param type 类型名称
* @param contents 更新内容
* @param ids 更新的id列表
* @param parent 父级
* @param routing 路由
* @return 结果对象
*/
BulkResponse bulkUpdate(String index, String type, List<String> ids, List<String> contents, String parent, String routing);
/**
* 批量更新。
* <p>
* 如果<code>routing</code>为null,则不设置路由。
*
* @param index 索引名称
* @param type 类型名称
* @param contents 更新内容
* @param ids 更新的id列表
* @param parent 父级
* @param routing 路由
* @param create 不存在,则创建文档。默认false
* @return 结果对象
*/
BulkResponse bulkUpdate(String index, String type, List<String> ids, List<String> contents, String parent, String routing, boolean create);
/**
* 删除。
* <p>
* 如果<code>routing</code>为null,则不设置路由。
*
* @param index 索引名称
* @param type 类型名称
* @param id id
* @return 删除结果
*/
DeleteResponse delete(String index, String type, String id);
/**
* 删除。
*
* @param index 索引名称
* @param type 类型名称
* @param id id
* @param routing 路由
* @param parent 关联父级
* @return 删除结果
*/
DeleteResponse delete(String index, String type, String id, String parent, String routing);
/**
* 批量删除。
*
* @param index 索引名称
* @param type 类型名称
* @param ids 被删除的id列表
* @return 删除结果
*/
BulkResponse bulkDelete(String index, String type, List<String> ids);
/**
* 带父id和路由的批量删除。
*
* @param index 索引名称
* @param type 类型名称
* @param ids id列表
* @param parent 父id
* @param routing 路由
* @return 删除结果
*/
BulkResponse bulkDelete(String index, String type, List<String> ids, String parent, String routing);
/**
* 搜索。
*
* @param index 索引名称
* @param type 类型名称
* @param searchSourceBuilder 设置好的结果字段过滤器
* @param query 设置好的查询构建器
* @param postFlter 设置好的查询过滤器
* @param from 开始位置,从0开始
* @param size 查询数量,默认为10
* @param aggregationBuilders 基于查询的聚合构建器
* @return 搜索结果
*/
SearchResponse search(String index, String type,
SearchSourceBuilder searchSourceBuilder,
QueryBuilder query, QueryBuilder postFlter,
Integer from, Integer size,
AggregationBuilder[] aggregationBuilders,
SortBuilder[] sortBuilders);
}
接口实现参照ES官网JAVA API的文档编写即可,search方法实现如下:
@Override
public SearchResponse search(String index, String type,
SearchSourceBuilder searchSourceBuilder,
QueryBuilder query, QueryBuilder postFlter,
Integer from, Integer size,
AggregationBuilder[] aggregationBuilders,
SortBuilder[] sortBuilders) {
if (!StringUtils.hasLength(index))
throw new IllegalArgumentException("Index name must not be null.");
SearchRequestBuilder requestBuilder = getClient().prepareSearch(index);
if (StringUtils.hasLength(type))
requestBuilder.setTypes(type);
if (searchSourceBuilder != null)
requestBuilder.setSource(searchSourceBuilder);
if (query != null)
requestBuilder.setQuery(query);
if (postFlter != null)
requestBuilder.setPostFilter(postFlter);
if (from == null)
from = 0;
if (size == null) // 默认为10,如果传入0表示不显示命中结果
size = 10;
requestBuilder.setFrom(from).setSize(size);
requestBuilder.setSearchType(SearchType.QUERY_THEN_FETCH);
// 聚合
if (aggregationBuilders != null && aggregationBuilders.length > 0) {
for (AggregationBuilder aggregationBuilder : aggregationBuilders) {
requestBuilder.addAggregation(aggregationBuilder);
}
}
// 排序
if (sortBuilders != null && sortBuilders.length > 0) {
for (SortBuilder sortBuilder : sortBuilders) {
requestBuilder.addSort(sortBuilder);
}
}
// 非格式化输出,日志就打印一行
Map<String, String> params = new HashMap<>();
params.put("pretty", "false");
ToXContent.MapParams mapParams = new ToXContent.MapParams(params);
log.info("===================== Searching params ===================== ");
log.info("index : " + index + ", type : " + type + ", from : " + from + ", size : " + size);
log.info("request : " + requestBuilder.request().source().toString(mapParams));
return requestBuilder.get();
}
至此,ES提供的JAVA API的底层操作已经编写完毕,供业务层调用。