用JAVA+ 微服务客户端写的一些查询,最近一直在研究ELK,对于 elasticsearch是特别感兴趣,并且是用得最多的,现在总结一下一些相关的 CURD语句,帮助我们快速完成一些常用数据分板等。
1 连接客户端的方式 有x-pack插件方式和没有安装插件方式不一样请对号入座,如果是生产上建议安装安全插件x-pack,
private static TransportClient client;
public static TransportClient getEsClient(){
//的是没有安装x-pack插件连接方式
Settings settings = Settings.builder().put("cluster.name","elasticsearch")//设置ES实例的名称
.put("client.transport.sniff", true) //自动嗅探整个集群的状态,把集群中其他ES节点的ip添加到本地的客户端列表中
.build();
client = new PreBuiltTransportClient(settings);//连接方式不一样,与x-pack插件有关
try {
client.addTransportAddress(new TransportAddress(InetAddress.getByName("192.168.11.237"),9300));
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("ElasticsearchClient 连接成功");
return client;
}
public static void closeClient(){
if(client!=null){
client.close();
}
}
2 建立索引和插入数据
public void insert(){
Map<String, String> map= new HashMap<String,String>();
map.put("prodId", "8");
map.put("prodName", "iphone8s");
map.put("prodDesc", "智能手机3");
client = ElasticsearchUtils.getEsClient();
//索引值不能有大写,同一个索引,类型必须相同, 要在同一个索引名称和类型下增加多数据,索引id必须不同,否则会覆盖
IndexResponse indexrespone = client.prepareIndex().setIndex(ElasticsearchUtils.getIndexName())//demo_index
.setType(ElasticsearchUtils.getTypeName())//同一个索引,类型必须相同
.setSource(map)
.setId("8")//相同索引类型,ID必须不一样
.execute()
.actionGet();
System.out.println("插入成功, isCreated="+indexrespone.getResult().toString());
ElasticsearchUtils.closeClient();
}
//增加
public void insert2(){
Map<String, String> map= new HashMap<String,String>();
map.put("name", "Jon someth_test");
map.put("gender", "male_test");
//获取服务器实态
client = ElasticsearchUtils.getEsClient();
//索引值不能有大写,同一个索引,类型必须相同, 要在同一个索引名称和类型下增加多数据,索引id必须不同,否则会覆盖
IndexResponse indexrespone = client.prepareIndex("index","type","2")//有不同参数构造函数
.setSource(map).get();//相同索引类型,ID必须不一样
System.out.println("插入成功, isCreated="+indexrespone.getResult().toString());
ElasticsearchUtils.closeClient();
}
2 查询索引下的所有数据,所有字段包含要查询的内容
//查询
public void query(){
client = ElasticsearchUtils.getEsClient();
//搜索数据
GetResponse response = client.prepareGet("blog", "article", "2").execute().actionGet();
System.out.println("blog get="+response.getSourceAsString());
//GetResponse responssse = client.prepareGet("java_demo_index", "java_demo_type", "1").execute().actionGet();
GetResponse getResponse = client.prepareGet().setIndex(ElasticsearchUtils.getIndexName())
.setType(ElasticsearchUtils.getTypeName())
.setId("1").execute().actionGet();
System.out.println("java_demo_index get="+getResponse.getSourceAsString());
ElasticsearchUtils.closeClient();
}
public void search(){
client = ElasticsearchUtils.getEsClient();
QueryBuilder query = QueryBuilders.queryStringQuery("iphone8s");
SearchResponse searchResponse = client.prepareSearch("demo_index")//ElasticsearchUtils.getIndexName()
.setQuery(query)
//.setOperationThreaded(false) operationThreaded 设置为 true 是在不同的线程里执行此次操作,配置线程
.setFrom(0).setSize(10)//相当于limit
.execute()
.actionGet();
//operationThreaded 设置为 true 是在不同的线程里执行此次操作
//SearchHits是SearchHit的复数形式,表示这个是一个列表
SearchHits shs = searchResponse.getHits();
for(SearchHit hit : shs){
System.out.println(hit.getSourceAsString());
}
ElasticsearchUtils.closeClient();
}
3 包含查询和范围查询
public void search2(){
client = ElasticsearchUtils.getEsClient();
QueryBuilder query2 = QueryBuilders.boolQuery()
.must(QueryBuilders.matchQuery("catId", "6"))
.must(QueryBuilders.termsQuery("catId", "6","7","8"))// 包含查询 第一个参数是字段后面是包含的数据 相当于 sql里的 in(6,7,8)
.must(QueryBuilders.rangeQuery("prodId").gte(5));//lte(5)小于等于5,gte(5)大于等于5的数据
SearchResponse searchRespone2 = client.prepareSearch(ElasticsearchUtils.getIndexName())
.setQuery(query2)
.setFrom(0).setSize(10)
.execute()
.actionGet();
SearchHits shs = searchRespone2.getHits();
for(SearchHit hit :shs){
System.out.println(hit.getSourceAsString());
}
ElasticsearchUtils.closeClient();
}
//多字段条件查询
QueryBuilder qb = multiMatchQuery("mac","description","name"); //mac是要搜索的词 description,name 都是字段 与termsQuery 正好相反的作用
List<String> strs=new ArrayList<>();
strs.add("kimchy14");
strs.add("kimchy15");
strs.add("kimchy16");
QueryBuilder qb=QueryBuilders.termsQuery("user",strs);
SearchRequestBuilder sv=client.prepareSearch("accounts").setTypes("person").setQuery(qb).setFetchSource("age",null).setFrom(0)
.setSize(100);
logger.log(Level.INFO,sv.toString());
SearchResponse response= sv.get();
SearchHits searchHits = response.getHits();
for(SearchHit hit:searchHits.getHits()){
logger.log(Level.INFO , hit.getSourceAsString());
}
4专门按id进行的包含查询
QueryBuilder qb=QueryBuilders.idsQuery(0+"");
SearchRequestBuilder sv=client.prepareSearch("accounts").setTypes("person").setQuery(qb).setFetchSource("age",null).setFrom(0)
.setSize(100);
logger.log(Level.INFO,sv.toString());
SearchResponse response= sv.get();
SearchHits searchHits = response.getHits();
for(SearchHit hit:searchHits.getHits()){
logger.log(Level.INFO , hit.getSourceAsString());
}
5 按通配符查询 或是模糊查询 通配符只能加在中间或者末尾 不能加在开头
QueryBuilder qb = QueryBuilders.wildcardQuery("user", "k*hy17*");
//Fuzziness fuzziness=Fuzziness.fromEdits(2);
// QueryBuilder qb = QueryBuilders.fuzzyQuery("user","mchy2").fuzziness(fuzziness);
//QueryBuilder qb = QueryBuilders.prefixQuery("user", "kimchy2");
SearchRequestBuilder sv=client.prepareSearch("accounts").setTypes("person").setQuery(qb).setFetchSource("user",null).setFrom(0)
.setSize(100);
logger.log(Level.INFO,sv.toString());
SearchResponse response= sv.get();
SearchHits searchHits = response.getHits();
for(SearchHit hit:searchHits.getHits()){
logger.log(Level.INFO , hit.getSourceAsString());
}
Fuzzy Query 模糊查询
QueryBuilder qb = fuzzyQuery(
"name",
"kimzhy"
)
6 过滤和排序
//过滤 和排序
public void filter(){
client = ElasticsearchUtils.getEsClient();
//设置查询参数,年龄条件,要求是from,大于50 to 小于60 返回的列表
//排序 multi_field
QueryBuilder postfilter = QueryBuilders.rangeQuery("prodId").gte(5).lte(8);
SearchResponse searchrespone = client.prepareSearch(ElasticsearchUtils.getIndexName())
.setPostFilter(postfilter)
.setFrom(0).setSize(10)
.addSort("prodId.keyword",SortOrder.DESC)
.execute()
.actionGet();
//SearchHits是SearchHit的复数形式,表示这个是一个列表
SearchHits shs = searchrespone.getHits();
for(SearchHit hit:shs){
System.out.println(hit.getSourceAsString());
}
ElasticsearchUtils.closeClient();
}
7 删除和查询删除批量删除等
//通过查询条件删除
public void deleteSearch(){
BulkByScrollResponse response =
DeleteByQueryAction.INSTANCE.newRequestBuilder(client)
.filter(QueryBuilders.matchQuery("gender", "male")) //查询条件
.source("persons") //index(索引名)
.get(); //执行
long deleted = response.getDeleted(); //删除文档的数量
}
//如果需要执行的时间比较长,可以使用异步的方式处理,结果在回调里面获取
public void deleteSearchBatch(){
DeleteByQueryAction.INSTANCE.newRequestBuilder(client)
.filter(QueryBuilders.matchQuery("gender", "male")) //查询
.source("persons") //index(索引名)
.execute(new ActionListener<BulkByScrollResponse>() { //回调监听
@Override
public void onResponse(BulkByScrollResponse response) {
long deleted = response.getDeleted(); //删除文档的数量
}
@Override
public void onFailure(Exception e) {
// Handle the exception
}
});
}
8 Upsert有数据就更新, 无数据就插入
//Upsert 更新插入,如果存在文档就更新,如果不存在就插入
public void updateInsert() throws IOException{
client = ElasticsearchUtils.getEsClient();
XContentBuilder jsonBuilder = XContentFactory.jsonBuilder();//帮助类,转成 json格式
IndexRequest indexRequest = new IndexRequest("index", "type")//可以省掉ID号, 默认查询所有索引ID
.source(jsonBuilder //此处查询条件可以省掉,默认查询所有属性类型
.startObject()
.field("name", "Jon someth_test")
.field("gender", "male_test")
.endObject());
UpdateRequest updateRequest = new UpdateRequest("index", "type", "2")
.doc(XContentFactory.jsonBuilder() //必须是新的实例,坑了很久,下面是更新的属性,没有的这个属性就增加,如果有就更新
.startObject()
.field("gender", "male_copy_test")
.endObject())
.upsert(indexRequest); //如果不存在此文档 ,就增加 `indexRequest`
try {
client.update(updateRequest).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
9 批量操作
//使用 Bulk Processor
//BulkProcessor 提供了一个简单的接口,在给定的大小数量上定时批量自动请求
public void BulkProcessor() throws IOException{
Client client = ElasticsearchUtils.getEsClient();
BulkProcessor bulkProcessor = BulkProcessor.builder(
client, //增加elasticsearch客户端
new BulkProcessor.Listener() {
@Override
public void beforeBulk(long executionId,
BulkRequest request) { System.out.println("执行前调用方法"); } //调用bulk之前执行 ,例如你可以通过request.numberOfActions()方法知道numberOfActions
@Override
public void afterBulk(long executionId,
BulkRequest request,
BulkResponse response) { System.out.println("执行后调用方法"); } //调用bulk之后执行 ,例如你可以通过request.hasFailures()方法知道是否执行失败
@Override
public void afterBulk(long executionId,
BulkRequest request,
Throwable failure) { System.out.println("执行失败抛Throwable调用方法"); } //调用失败抛 Throwable
})
.setBulkActions(10000) //每次10000请求
.setBulkSize(new ByteSizeValue(5, ByteSizeUnit.MB)) //拆成5mb一块
.setFlushInterval(TimeValue.timeValueSeconds(5)) //无论请求数量多少,每5秒钟请求一次。
.setConcurrentRequests(1) //设置并发请求的数量。值为0意味着只允许执行一个请求。值为1意味着允许1并发请求。
.setBackoffPolicy(
BackoffPolicy.exponentialBackoff(TimeValue.timeValueMillis(100), 3))//设置自定义重复请求机制,最开始等待100毫秒,之后成倍更加,重试3次,当一次或多次重复请求失败后因为计算资源不够抛出 EsRejectedExecutionException 异常,可以通过BackoffPolicy.noBackoff()方法关闭重试机制
.build();
/* BulkProcessor 默认设置
bulkActions 1000
bulkSize 5mb
不设置flushInterval
concurrentRequests 为 1 ,异步执行
backoffPolicy 重试 8次,等待50毫秒*/
bulkProcessor.add(new IndexRequest("twitter", "tweet", "1").source("your doc here 需要插入的文件和资源"));
bulkProcessor.add(new DeleteRequest("twitter", "tweet", "2"));//删除一个索引
bulkProcessor.close(); //关闭操作
}
10 Stats 聚合操作 count min max avg sum
private static void stats(TransportClient client) {
SearchRequestBuilder search = client.prepareSearch("mytest_1").setTypes("test");
SearchResponse sr = search.addAggregation(AggregationBuilders.stats("price_stats").field("price")).execute().actionGet();
Stats stats = sr.getAggregations().get("price_stats");
System.out.println(stats.getAvgAsString());
System.out.println(stats.getMaxAsString());
System.out.println(stats.getMinAsString());
System.out.println(stats.getSumAsString());
}
这些是一些日常用到的方法,熟练使用后基本没有什么问题,当然还有更多操作数据的方法,我就不上传了,在github上放着
最后总结如下 精确查询用term 组合查询用bool 范围用range and查询用must or查询用should not查询用must not 常见的接收聚合返回结果的类型 ValueCount AVG SUM MAX MIN 按照英文意义就可以理解 分组聚合查询时候还需要根据实际情况看是返回那种terms