Elasticsearch Java高级客户端
1.? 概述 Java REST Client 有两种风格:
(PS:所谓低级与高级,我觉得一个很形象的比喻是,面向过程编程与面向对象编程) 在 Elasticsearch 7.0 中不建议使用TransportClient,并且在8.0中会完全删除TransportClient。因此,官方更建议我们用Java High Level REST Client,它执行HTTP请求,而不是序列号的Java请求。既然如此,这里就直接用高级了。 ? 2.??Java High Level REST Client (高级REST客户端) 2.1.? Maven仓库 <dependency> groupId>org.elasticsearch.client</artifactId>elasticsearch-rest-high-level-clientversion>6.5.4> > 2.2.? 依赖
2.3.? 初始化 RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( new HttpHost("localhost",9200,"http"), 高级客户端内部会创建低级客户端用于基于提供的builder执行请求。低级客户端维护一个连接池,并启动一些线程,因此当你用完以后应该关闭高级客户端,并且在内部它将会关闭低级客户端,以释放这些资源。关闭客户端可以使用close()方法: client.close(); ? 2.4.? 文档API 2.4.1.? 添加文档 IndexRequest IndexRequest request = new IndexRequest("posts","doc","1"); String jsonString = "{"user":"kimchy","postDate":"2013-01-30","message":"trying out Elasticsearch"}"; request.source(jsonString,XContentType.JSON); 提供文档source的方式还有很多,比如: 通过Map的方式提供文档source 通过XContentBuilder方式提供source 通过Object的方式(键值对)提供source 可选参数 同步执行 异步执行 你也可以异步执行 IndexRequest,为此你需要指定一个监听器来处理这个异步响应结果: 一个典型的监听器看起来是这样的: IndexResponse 如果有版本冲突,将会抛出ElasticsearchException 同样的异常也有可能发生在当opType设置为create的时候,且相同索引、相同类型、相同ID的文档已经存在时。例如: ? 2.4.2.? 查看文档 Get Request 可选参数 同步执行 异步执行 Get Response 当索引不存在,或者指定的文档的版本不存在时,响应状态吗是404,并且抛出ElasticsearchException ? 2.4.3.? 文档是否存在 ? 2.4.4.? 删除文档 Delete Request 可选参数 同添加 ? 2.5.? 搜索API Search Request 基本格式是这样的: 大多数查询参数被添加到?SearchSourceBuilder 可选参数 SearchSourceBuilder 控制检索行为的大部分选项都可以在SearchSourceBuilder中设置。下面是一个常见选项的例子: 在这个例子中,我们首先创建了一个SearchSourceBuilder对象,并且带着默认选项。然后设置了一个term查询,接着设置检索的位置和数量,最后设置超时时间 在设置完这些选项以后,我们只需要把SearchSourceBuilder加入到SearchRequest中即可 ? 构建Query 用QueryBuilder来创建Serarch Query。QueryBuilder支持Elasticsearch DSL中每一种Query 例如: 还可以通过QueryBuilders工具类来创建QueryBuilder对象,例如: 无论是用哪种方式创建,最后一定要把QueryBuilder添加到SearchSourceBuilder中 ? 排序 SearchSourceBuilder 可以添加一个或多个 SortBuilder SortBuilder有四种实现:FieldSortBuilder、GeoDistanceSortBuilder、ScoreSortBuilder、ScriptSortBuilder ? 聚集函数 同步执行 异步执行 从查询响应中取出文档 ? 3.? 示例 3.1.? 准备数据 3.1.1.? 安装IK分词器插件 ./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.5.4/elasticsearch-analysis-ik-6.5.4.zip 3.1.2.? 创建索引 curl -X PUT "localhost:9200/book" -H 'Content-Type: application/json' -d' { mappings":{ _doc:{ properties:{ id:{ type":integer },nametext,1)">analyzerik_max_wordsearch_analyzerauthorcategorypricedoublestatusshortsellReasonsellTimedateformatyyyy-MM-dd } } } } } ' 3.1.3.? 数据预览 ? 3.2.? 示例代码 3.2.1.? 完整的pom.xml <?xml version="1.0" encoding="UTF-8"?> project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"modelVersion>4.0.0parent> >org.springframework.boot>spring-boot-starter-parent>2.1.1.RELEASErelativePath/> <!-- lookup parent from repository --> >com.cjs.example>elasticsearch-demo>0.0.1-SNAPSHOTnamedescription></> propertiesjava.version>1.8dependencies> >spring-boot-starter-web>spring-boot-starter-thymeleaf> >org.apache.commons>commons-lang3>3.8>com.alibaba>fastjson>1.2.54>ch.qos.logback>logback-core>1.2.3>org.projectlombok>lombokoptional>true>spring-boot-starter-testscope>testbuildpluginsplugin> >spring-boot-maven-plugin> project> 3.2.2.? 配置 package com.cjs.example.elasticsearch.config; import org.apache.http.HttpHost; org.elasticsearch.client.RestClient; org.elasticsearch.client.RestHighLevelClient; org.springframework.context.annotation.Bean; org.springframework.context.annotation.Configuration; /** * @author ChengJianSheng * @date 2019-01-07 */ @Configuration public class ElasticsearchClientConfig { @Bean public RestHighLevelClient restHighLevelClient() { RestHighLevelClient client = RestHighLevelClient( RestClient.builder( ))); return client; } } 3.2.3.? domain com.cjs.example.elasticsearch.domain.model; lombok.Data; java.io.Serializable; * 图书 * @Data class BookModel implements Serializable { private Integer id; 图书ID private String name; 图书名称 private String author; 作者 private Integer category; 图书分类 private Double price; 图书价格 private String sellReason; 上架理由 private String sellTime; 上架时间 private Integer status; 状态(1:可售,0:不可售) } 3.2.4.? Controller com.cjs.example.elasticsearch.controller; com.alibaba.fastjson.JSON; com.cjs.example.elasticsearch.domain.common.BaseResult; com.cjs.example.elasticsearch.domain.common.Page; com.cjs.example.elasticsearch.domain.model.BookModel; com.cjs.example.elasticsearch.domain.vo.BookRequestVO; com.cjs.example.elasticsearch.service.BookService; lombok.extern.slf4j.Slf4j; org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; * 文档操作 * @Slf4j @RestController @RequestMapping("/book") BookController { @Autowired private BookService bookService; * 列表分页查询 @GetMapping("/list") BaseResult list(BookRequestVO bookRequestVO) { Page<BookModel> page = bookService.list(bookRequestVO); if (null == page) { BaseResult.error(); } BaseResult.ok(page); } * 查看文档 @GetMapping("/detail" BaseResult detail(Integer id) { id) { return BaseResult.error("ID不能为空"); } BookModel book = bookService.detail(id); BaseResult.ok(book); } * 添加文档 @PostMapping("/add" BaseResult add(@RequestBody BookModel bookModel) { bookService.save(bookModel); log.info("插入文档成功!请求参数: {}" BaseResult.ok(); } * 修改文档 @PostMapping("/update" BaseResult update(@RequestBody BookModel bookModel) { Integer id = bookModel.getId(); book) { return BaseResult.error("记录不存在"); } bookService.update(bookModel); log.info("更新文档成功!请求参数: {}" * 删除文档 @GetMapping("/delete" BaseResult delete(Integer id) { ); } bookService.delete(id); BaseResult.ok(); } } 3.2.5.? Service com.cjs.example.elasticsearch.service.impl; org.apache.commons.lang3.StringUtils; org.elasticsearch.action.ActionListener; org.elasticsearch.action.DocWriteResponse; org.elasticsearch.action.delete.DeleteRequest; org.elasticsearch.action.delete.DeleteResponse; org.elasticsearch.action.get.GetRequest; org.elasticsearch.action.get.GetResponse; org.elasticsearch.action.index.IndexRequest; org.elasticsearch.action.index.IndexResponse; org.elasticsearch.action.search.SearchRequest; org.elasticsearch.action.search.SearchResponse; org.elasticsearch.action.support.replication.ReplicationResponse; org.elasticsearch.action.update.UpdateRequest; org.elasticsearch.action.update.UpdateResponse; org.elasticsearch.client.RequestOptions; org.elasticsearch.common.unit.TimeValue; org.elasticsearch.index.query.BoolQueryBuilder; org.elasticsearch.index.query.QueryBuilders; org.elasticsearch.rest.RestStatus; org.elasticsearch.search.SearchHit; org.elasticsearch.search.SearchHits; org.elasticsearch.search.builder.SearchSourceBuilder; org.elasticsearch.search.sort.FieldSortBuilder; org.elasticsearch.search.sort.SortOrder; org.springframework.stereotype.Service; org.springframework.util.CollectionUtils; java.io.IOException; import java.util.*; java.util.stream.Collectors; @Slf4j @Service class BookServiceImpl BookService { private static final String INDEX_NAME = "book"; final String INDEX_TYPE = "_doc"; @Autowired RestHighLevelClient client; @Override public Page<BookModel> list(BookRequestVO bookRequestVO) { int pageNo = bookRequestVO.getPageNo(); int pageSize = bookRequestVO.getPageSize(); SearchSourceBuilder sourceBuilder = SearchSourceBuilder(); sourceBuilder.from(pageNo - 1); sourceBuilder.size(pageSize); sourceBuilder.sort(new FieldSortBuilder("id").order(SortOrder.ASC)); sourceBuilder.query(QueryBuilders.matchAllQuery()); BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); if (StringUtils.isNotBlank(bookRequestVO.getName())) { boolQueryBuilder.must(QueryBuilders.matchQuery("name" (StringUtils.isNotBlank(bookRequestVO.getAuthor())) { boolQueryBuilder.must(QueryBuilders.matchQuery("author"null != bookRequestVO.getStatus()) { boolQueryBuilder.must(QueryBuilders.termQuery("status" (StringUtils.isNotBlank(bookRequestVO.getSellTime())) { boolQueryBuilder.must(QueryBuilders.termQuery("sellTime" (StringUtils.isNotBlank(bookRequestVO.getCategories())) { String[] categoryArr = bookRequestVO.getCategories().split(","); List<Integer> categoryList = Arrays.asList(categoryArr).stream().map(e->Integer.valueOf(e)).collect(Collectors.toList()); BoolQueryBuilder categoryBoolQueryBuilder = QueryBuilders.boolQuery(); for (Integer category : categoryList) { categoryBoolQueryBuilder.should(QueryBuilders.termQuery("category" SearchRequest(); searchRequest.indices(INDEX_NAME); searchRequest.source(sourceBuilder); try { SearchResponse searchResponse = client.search(searchRequest,RequestOptions.DEFAULT); RestStatus restStatus = searchResponse.status(); if (restStatus != RestStatus.OK) { return null; } List<BookModel> list = new ArrayList<>(); SearchHits searchHits = searchResponse.getHits(); (SearchHit hit : searchHits.getHits()) { String source = hit.getSourceAsString(); BookModel book = JSON.parSEObject(source,BookModel.); list.add(book); } long totalHits = searchHits.getTotalHits(); Page<BookModel> page = new Page<>(pageNo,pageSize,totalHits,list); TimeValue took = searchResponse.getTook(); log.info("查询成功!请求参数: {},用时{}毫秒" page; } catch (IOException e) { log.error("查询失败!原因: {}"; } @Override void save(BookModel bookModel) { Map<String,Object> jsonMap = new HashMap<>(); jsonMap.put("id" IndexRequest(INDEX_NAME,INDEX_TYPE,String.valueOf(bookModel.getId())); indexRequest.source(jsonMap); client.indexAsync(indexRequest,RequestOptions.DEFAULT,1)">new ActionListener<IndexResponse>() { @Override onResponse(IndexResponse indexResponse) { String index = indexResponse.getIndex(); String type = indexResponse.getType(); String id = indexResponse.getId(); long version = indexResponse.getVersion(); log.info("Index: {},Type: {},Id: {},Version: {}"if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) { log.info("写入文档"); } else DocWriteResponse.Result.UPDATED) { log.info("修改文档"); } ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo(); if (shardInfo.getTotal() != shardInfo.getSuccessful()) { log.warn("部分分片写入成功"); } if (shardInfo.getFailed() > 0) { (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) { String reason = failure.reason(); log.warn("失败原因: {}" onFailure(Exception e) { log.error(e.getMessage(),e); } }); } @Override update(BookModel bookModel) { Map<String,1)">(); jsonMap.put("sellReason" UpdateRequest(INDEX_NAME,String.valueOf(bookModel.getId())); request.doc(jsonMap); { UpdateResponse updateResponse = client.update(request,RequestOptions.DEFAULT); } (IOException e) { log.error("更新失败!原因: {}"void delete(int id) { DeleteRequest request = DeleteRequest(INDEX_NAME,String.valueOf(id)); { DeleteResponse deleteResponse = client.delete(request,RequestOptions.DEFAULT); if (deleteResponse.status() == RestStatus.OK) { log.info("删除成功!id: {}" (IOException e) { log.error("删除失败!原因: {}"public BookModel detail( id) { GetRequest getRequest = GetRequest(INDEX_NAME,1)"> { GetResponse getResponse = client.get(getRequest,1)"> (getResponse.isExists()) { String source = getResponse.getSourceAsString(); BookModel book = JSON.parSEObject(source,1)">); book; } } (IOException e) { log.error("查看失败!原因: {}"; } } 3.2.6.? 页面 <!DOCTYPE htmlhtml lang="zh"headmeta charset="UTF-8"title>图书列表link rel="stylesheet" href="/bootstrap-4/css/bootstrap.min.css"="/bootstrap-table/bootstrap-table.css"script src="jquery-3.3.1.min.js"script="/bootstrap-4/js/bootstrap.min.js"="/bootstrap-table/bootstrap-table.js"="/bootstrap-table/locale/bootstrap-table-zh-CN.js"> $(function(){ $('#table).bootstrapTable({ url: /book/listgetserver(res) { // 加载服务器数据之前的处理程序,可以用来格式化数据。参数:res为从服务器请求到的数据。 var result = {}; result.total res.data.totalCount; result.rows res.data.pageList; return result; },pagination: true3 初始PageSize queryParams: (params) { req { pageSize: params.limit,pageNo: params.offset + 1 }; req; },striped: idIDname名称author作者price单价sellTime上架时间status状态(value) { if (value == ) { return <span style="color: green">可售</span>; } else { <span style="color: red">不可售</span>; } } },1)">category分类10010中国当代小说else 10011武侠小说10012爱情小说10013中国当代随笔sellReason上架理由操作() { <a href="#">修改</a> <a href="#">删除</a>; } } ] }); }); bodydiv ="table-responsive" style="padding: 10px 30px"table id="table" class="table text-nowrap"tabledivhtml> 3.3.? 演示 重点演示几个查询 返回结果: { "code": 200,"success": true,"msg": "SUCCESS","data": { "pageNumber": 1,"pageSize": 10,"totalCount": 2,"pageList": [ { "id": 2,"name": "倚天屠龙记(全四册)","author": "金庸","category": 10011,"price": 70.4,"sellReason": "武林至尊,宝刀屠龙,号令天下,莫敢不从。","sellTime": "2018-11-11","status": 1 },{ "id": 3,"name": "神雕侠侣","price": 70,"sellReason": "风陵渡口初相遇,一见杨过误终身","status": 1 } ] } } 上面的查询对应的Elasticsearch DSL是这样的: { "from":0,"size":10,"query":{ "bool":{ "must":[ { "match":{ "author":{ "query":"金庸","operator":"OR","prefix_length":0,"max_expansions":50,"fuzzy_transpositions":true,"lenient":false,"zero_terms_query":"NONE","auto_generate_synonyms_phrase_query":true,"boost":1 } } },{ "term":{ "status":{ "value":1,{ "bool":{ "should":[ { "term":{ "category":{ "value":10010,"boost":1 } } },{ "term":{ "category":{ "value":10011,{ "term":{ "category":{ "value":10012,"boost":1 } } } ],"adjust_pure_negative":true,"boost":1 } } ],"boost":1 } },"sort":[ { "id":{ "order":"asc" } } ] } 3.4.? 工程结构 ? 4.? 参考 https://github.com/medcl/elasticsearch-analysis-ik https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-search.html https://bootstrap-table.wenzhixin.net.cn/documentation/ ? 5.? 其它相关 《Elasticsearch 分词器》 《Elasticsearch Document》 《Elasticsearch Search API》 《Elasticsearch查询》 《Elasticsearch Mapping》 《SpringBoot+Elasticsearch》 《ELK快速搭建日志平台》 ? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 俊六弦 的提问《git for windows 使用 git bash here 执行
- XMLStarlet 命令行操作xml利器
- sencha-touch-2 – Sencha Touch 2,嵌套XML解析nodeValue
- Swift利用代理 正向、反向传值
- ruby-on-rails – Ruby on Rails下拉框的静态列表选项
- c# – StackExchange.Redis中是否提供原始命令?
- c# – 使用LINQ进行Lazily分区序列
- Oracle Solaris 11 x64 root密码?
- re-正则表达式模块
- ruby-on-rails – 在Rails应用程序中为管理界面定义单独的视