# elasticsearch学习实战项目 **Repository Path**: satan1996/elasticsearch-learn ## Basic Information - **Project Name**: elasticsearch学习实战项目 - **Description**: 个人基于elasticsearch8.x版本的学习记录包含最新的api操作文档和项目实战代码 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 5 - **Forks**: 1 - **Created**: 2024-02-19 - **Last Updated**: 2025-05-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Elasticsearch8学习笔记 ## 一、安装elasticsearch和kibana ### 1.1.编写elasticsearch.yaml文件 ```yaml # 版本信息:2.2 services: # Elasticsearch 服务配置 Elasticsearch: # 镜像名称:elasticsearch:8.12.0 image: elasticsearch:8.12.0 # 容器名称:elasticsearch container_name: elasticsearch # 数据卷挂载 volumes: - /home/docker/container/elasticsearch/data:/usr/share/elasticsearch/data - /home/docker/container/elasticsearch/logs:/usr/share/elasticsearch/logs - /home/docker/container/elasticsearch/config:/usr/share/elasticsearch/config - /home/docker/container/elasticsearch/plugins:/usr/share/elasticsearch/plugins # 端口映射:将本地的 9200 端口映射到容器的 9200 端口 ports: - 9200:9200 # 环境变量设置 environment: - node.name=single-node - cluster.name=docker-cluster - discovery.type=single-node - bootstrap.memory_lock=true - xpack.security.enabled=false # 内存限制:1GB mem_limit: 1g # ulimits 设置:解锁内存锁定 ulimits: memlock: soft: -1 hard: -1 # 健康检查:使用 CMD-SHELL 执行 curl 命令检查 Elasticsearch 是否运行正常 healthcheck: test: [ "CMD-SHELL", "curl -s http://localhost:9200 | grep -q 'elasticsearch'", ] interval: 10s timeout: 10s retries: 120 # Kibana 服务配置 kibana: # 依赖 Elasticsearch 服务 depends_on: - elasticsearch # 镜像名称:kibana:8.12.0 image: kibana:8.12.0 # 容器名称:kibana container_name: kibana # 数据卷挂载 volumes: - /home/docker/container/kibana/data:/usr/share/kibana/data - /home/docker/container/kibana/logs:/usr/share/kibana/logs - /home/docker/container/kibana/config:/usr/share/kibana/config - /home/docker/container/kibana/plugins:/usr/share/kibana/plugins # 端口映射:将本地的 5601 端口映射到容器的 5601 端口 ports: - 5601:5601 # 环境变量设置 environment: - SERVERNAME=kibana - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 # 内存限制:1GB mem_limit: 1g # 健康检查:使用 CMD-SHELL 执行 curl 命令检查 Kibana 是否运行正常 healthcheck: test: [ "CMD-SHELL", "curl -s -I http://localhost:5601 | grep -q 'HTTP/1.1 302 Found'", ] interval: 10s timeout: 10s retries: 120 ``` ### 1.2.安装ik分词器 [下载地址](https://github.com/medcl/elasticsearch-analysis-ik/releases) 解压后重命名放入以下位置 image-20240219110330017 ### 1.3.启动容器命令 ```shell docker compose -f elasticsearch.yaml up -d ``` ### 1.4.启动效果(portainer控制台) ![image-20240219090420463](assets/image-20240219090420463.png) ## 二、springboot整合elasticsearch8.x ### 2.1.springboot项目引入依赖 ```xml co.elastic.clients elasticsearch-java ``` ### 2.2.配置客户端 #### 2.2.1.application.yaml定义参数 ```yaml elasticsearch: host: 192.168.120.130 port: 9200 ``` #### 2.2.2.java代码中配置 ```java @Configuration public class EsConfig { @Value("${elasticsearch.host}") private String hostname; @Value("${elasticsearch.port}") private int port; /** * 创建一个ElasticsearchClient实例,并将其注册为Bean。 * @return ElasticsearchClient实例 */ @Bean public ElasticsearchClient elasticsearchClient() { // 创建一个HttpHost实例,用于指定Elasticsearch的主机和端口 HttpHost httpHost = HttpHost.create(hostname + ":" + port); // 创建一个RestClient实例,用于与Elasticsearch进行通信 RestClient restClient = RestClient.builder(httpHost).build(); // 创建一个RestClientTransport实例,用于将RestClient与Elasticsearch连接起来 RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper()); // 创建一个ElasticsearchClient实例,并传入RestClientTransport对象 return new ElasticsearchClient(transport); } /** * 创建一个ElasticsearchAsyncClient实例,并将其注册为Bean。 * @return ElasticsearchAsyncClient实例 */ @Bean public ElasticsearchAsyncClient elasticsearchAsyncClient() { // 创建一个HttpHost实例,用于指定Elasticsearch的主机和端口 HttpHost httpHost = HttpHost.create(hostname + ":" + port); // 创建一个RestClient实例,用于与Elasticsearch进行通信 RestClient restClient = RestClient.builder(httpHost).build(); // 创建一个RestClientTransport实例,用于将RestClient与Elasticsearch连接起来 RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper()); // 创建一个ElasticsearchAsyncClient实例,并传入RestClientTransport对象 return new ElasticsearchAsyncClient(transport); } } ``` ### 2.3.代码中引入客户端 ```java @Autowired private ElasticsearchClient client; ``` ## 三、RestAPI ### 3.1.创建索引库 #### 3.1.1.方式一 - 编写some-index.json文件放到src/main/resources目录下 ```json { "mappings": { "properties": { "id": { "type": "keyword" }, "name": { "type": "text", "analyzer": "ik_max_word", "copy_to": "all" }, "address": { "type": "keyword", "index": false }, "price": { "type": "integer" }, "score": { "type": "integer" }, "brand": { "type": "keyword", "copy_to": "all" }, "city": { "type": "keyword", "copy_to": "all" }, "starName": { "type": "keyword" }, "business": { "type": "keyword" }, "location": { "type": "geo_point" }, "pic": { "type": "keyword", "index": false }, "all": { "type": "text", "analyzer": "ik_max_word" } } } } ``` - 创建文档类型实体类HotelDoc.java ```java @Data @NoArgsConstructor @AllArgsConstructor public class HotelDoc { @Schema(description = "酒店id") private Long id; @Schema(description = "酒店名称") private String name; @Schema(description = "酒店地址") private String address; @Schema(description = "酒店价格") private Integer price; @Schema(description = "酒店评分") private Integer score; @Schema(description = "酒店品牌") private String brand; @Schema(description = "酒店城市") private String city; @Schema(description = "酒店星级") private String starName; @Schema(description = "酒店商圈") private String business; @Schema(description = "酒店经纬度") private String location; @Schema(description = "酒店图片") private String pic; // 排序时的 距离值 @Schema(description = "距离值") private Object distance; @Schema(description = "是否广告位") private Boolean isAD; @Schema(description = "建议词") private List suggestion; public HotelDoc(Hotel hotel) { this.id = hotel.getId(); this.name = hotel.getName(); this.address = hotel.getAddress(); this.price = hotel.getPrice(); this.score = hotel.getScore(); this.brand = hotel.getBrand(); this.city = hotel.getCity(); this.starName = hotel.getStarName(); this.business = hotel.getBusiness(); this.location = hotel.getLatitude() + ", " + hotel.getLongitude(); this.pic = hotel.getPic(); final String regex = "[\\u4e00-\\u9fa5]+"; final Pattern pattern = Pattern.compile(regex); if (hotel.getBusiness().isEmpty()) { this.suggestion = Arrays.asList(this.brand); } else { this.suggestion = new ArrayList<>(); this.suggestion.add(this.brand); Matcher matcher = pattern.matcher(hotel.getBusiness()); while (matcher.find()) { this.suggestion.add(matcher.group()); } } } } ``` - 编写java代码 ```java /** * 测试创建索引 * @throws IOException */ @Test public void createIndex1() throws IOException { // 创建一个InputStream对象,用于读取索引配置文件 InputStream input = new FileInputStream(new File("src/main/resources/some-index.json")); // 创建一个CreateIndexRequest对象,用于指定索引名称和索引配置文件 CreateIndexRequest req = CreateIndexRequest.of(b -> b .index("some-index") .withJson(input) ); // 调用Elasticsearch客户端的create方法创建索引,并获取返回结果 boolean created = client.indices().create(req).acknowledged(); // 根据创建结果输出相应的信息 if (created) { System.out.println("创建成功"); } else { System.out.println("创建失败"); } } ``` #### 3.1.2.方式二 - 编写java类HotelIndexConsts.java ```java public class HotelIndexConsts { public static final String MAPPING_TEMPLATE = """ { "mappings": { "properties": { "id": { "type": "keyword" }, "name": { "type": "text", "analyzer": "ik_max_word", "copy_to": "all" }, "address": { "type": "keyword", "index": false }, "price": { "type": "integer" }, "score": { "type": "integer" }, "brand": { "type": "keyword", "copy_to": "all" }, "city": { "type": "keyword", "copy_to": "all" }, "starName": { "type": "keyword" }, "business": { "type": "keyword" }, "location": { "type": "geo_point" }, "pic": { "type": "keyword", "index": false }, "all": { "type": "text", "analyzer": "ik_max_word" } } } } """; } ``` - 编写java代码 ```java @Test public void createIndex2() throws IOException { //创建Reader Reader reader = new StringReader(HotelIndexConsts.MAPPING_TEMPLATE); CreateIndexRequest req = CreateIndexRequest.of(b -> b .index("some-index") .withJson(reader) ); boolean created = client.indices().create(req).acknowledged(); if (created) { System.out.println("创建成功"); } else { System.out.println("创建失败"); } } ``` ### 3.2.删除索引库 ```java @Test public void deleteIndex() throws IOException { // 创建删除索引请求 DeleteIndexRequest request = DeleteIndexRequest.of(b -> b.index("some-index")); // 发送删除索引请求并获取响应 DeleteIndexResponse response = client.indices().delete(request); // 判断删除是否成功 if (response.acknowledged()) { System.out.println("删除成功"); } else { System.out.println("删除失败"); } } ``` ### 3.3.判断索引是否存在 ```java @Test public void testExistsIndex() throws IOException { // 创建ExistsRequest对象,指定要查询的索引库名称 ExistsRequest request = ExistsRequest.of(b -> b.index("hotel")); // 发送查询请求,获取索引库是否存在 BooleanResponse response = client.indices().exists(request); // 输出查询结果 System.out.println(response.value()?"索引存在":"索引不存在"); } ``` ## 四、操作文档 ### 4.1.新增文档 ```java @Test public void testAddDocument() throws IOException { // 1. 根据id查询酒店数据 Hotel hotel = hotelService.getById(61083L); // 2. 将酒店数据转换为文档类型(HotelDoc) HotelDoc hotelDoc = new HotelDoc(hotel); // 3. 将HotelDoc对象转换为JSON格式字符串 String json = JSON.toJSONString(hotelDoc); // 4. 准备索引请求对象 IndexResponse response = client.index(i -> i .index("hotel") // 设置索引名称为"hotel" .id(hotelDoc.getId().toString()) // 设置文档id .document(hotelDoc) // 设置待索引的文档对象 ); log.info("已成功索引,版本号为:" + response.version()); } ``` ### 4.2.查询文档 ```java @Test public void getIndex() throws IOException { // 1. 准备GetIndexRequest对象 GetIndexRequest request = GetIndexRequest.of(b -> b.index("hotel")); // 2. 准备并发送获取请求,获取响应对象(GetResponse) GetResponse getResponse = client.get(i -> i.index("hotel").id("61083"), HotelDoc.class); // 3. 从响应对象中获取原始文档数据(HotelDoc类型) HotelDoc hotelDoc = getResponse.source(); // 4. 打印获取到的HotelDoc对象内容 System.out.println(hotelDoc); } ``` ### 4.3.删除文档 ```java /** * 测试方法,用于从酒店索引中删除指定文档。 * * @throws IOException 如果发生输入输出错误,则抛出此异常 */ @Test void testDeleteDocument() throws IOException { // 1. 准备 DeleteRequest 对象,设置要删除的文档所在索引为 "hotel",以及文档ID为 "36934" DeleteResponse response = client.delete(i -> i.index("hotel").id("36934")); // 2. 输出 DeleteResponse 对象中的结果状态 System.out.println(response.result()); } ``` ### 4.4.修改文档 ```java @Test public void testUpdateDocument() throws IOException { // 1.根据id查询酒店数据 Hotel hotel = hotelService.getById(61083L); // 2.转换为文档类型 HotelDoc hotelDoc = new HotelDoc(hotel); hotelDoc.setPrice(1000); // 1.准备Request对象 IndexResponse response = client.index(i -> i .index("hotel") .id("61083") .document(hotelDoc) ); System.out.println("response.result() = " + response.result()); } ``` ### 4.5.批量导入文档 ```java @Test void testBulkRequest() throws IOException { // 从服务中查询并获取所有酒店数据 List hotels = hotelService.list(); // 初始化一个批量操作列表,用于存储待执行的Elasticsearch批量操作 List bulkOperations = new ArrayList<>(); // 对查询到的所有酒店进行遍历,并为每个酒店创建一个新的HotelDoc实例 hotels.stream().forEach(hotel -> { HotelDoc hotelDoc = new HotelDoc(hotel); // 创建一个批量操作,设置索引、文档内容(HotelDoc对象)以及文档ID BulkOperation operation = BulkOperation.of(b -> b.index(c -> c.document(hotelDoc).id(hotelDoc.getId().toString()))); // 将创建好的批量操作添加到批量操作列表中 bulkOperations.add(operation); }); // 使用Elasticsearch客户端执行批量请求,索引名称为"hotel",并将之前构建的所有批量操作应用于该请求 BulkResponse response = client.bulk(b -> b.index("hotel").operations(bulkOperations)); // 打印出批量请求响应中的每个项目结果 response.items().forEach(System.out::println); } ``` ## 五、查询文档 ### 5.1.match_all查询 ```java @Test void testMatchAll() throws IOException { // 使用客户端执行对"hotel"索引的搜索,其中查询语句为匹配所有文档(Match All Query) SearchResponse searchResponse = client.search(s -> s.index("hotel") .query(a->a.matchAll(MatchAllQuery.of(b->b.queryName("")))), HotelDoc.class); // 处理并解析搜索响应结果 handleResponse(searchResponse); } ``` ### 5.2.match查询 ```java @Test void testMatch() throws IOException { // 创建一个针对“hotel”索引的搜索请求,其中包含一个match查询条件 SearchRequest request = SearchRequest.of(b -> b .index("hotel") .query(q -> q.match(m -> m.field("all").query("如家"))) // 设置查询字段为"all",查询关键词为"如家" ); // 执行搜索并获取响应结果,类型为HotelDoc的SearchResponse对象 SearchResponse searchResponse = client.search(request, HotelDoc.class); // 处理搜索响应结果 handleResponse(searchResponse); } ``` ### 5.3.multiMatch多字段查询 ```java @Test void testMultiMatch() throws IOException { // 创建一个多字段匹配查询的搜索请求,索引为"hotel",查询字段包括"name"和"business",查询关键词为"如家" SearchRequest request = SearchRequest.of(b -> b .index("hotel") .query(q -> q.multiMatch(a->a.fields("name","business").query("如家")))); // 执行搜索并获取包含HotelDoc类型结果的响应 SearchResponse searchResponse = client.search(request, HotelDoc.class); // 处理搜索响应内容 handleResponse(searchResponse); } ``` ### 5.4.精确查询 ```java @Test void testTermMatchTest() throws IOException { // 创建一个带有term匹配查询的搜索请求 SearchRequest request = SearchRequest.of(b -> b .index("hotel") .query(q -> q.term(t -> t.field("city").value("上海"))) ); // 执行搜索并获取响应 SearchResponse searchResponse = client.search(request, HotelDoc.class); // 处理响应 handleResponse(searchResponse); } ``` ### 5.5.范围查询 ```java /** * 范围查询 */ @Test void testRange() throws IOException { // 构造搜索请求 SearchRequest request = SearchRequest.of(b -> b .index("hotel") .query(q -> q.range(r -> r.field("price").gte(JsonData.of(1000)).lte(JsonData.of(2000))))); // 执行搜索 SearchResponse searchResponse = client.search(request, HotelDoc.class); // 处理搜索结果 handleResponse(searchResponse); } ``` ### 5.6.布尔查询 ```java /** * 布尔查询 */ @Test void testBool() throws IOException { // 构造搜索请求 SearchRequest request = SearchRequest.of(b -> b .index("hotel") .query(q -> q.bool(bq -> bq.must(m -> m.term(t -> t.field("city").value("上海"))).filter(f -> f.range(r -> r.field("price").lte(JsonData.of(250)))))) ); // 执行搜索 SearchResponse searchResponse = client.search(request, HotelDoc.class); // 处理搜索结果 handleResponse(searchResponse); } ``` ### 5.7.排序、分页 ```java /** * 进行分页查询的测试方法 */ @Test void testPageAndSort() throws IOException { // 定义当前页码和每页显示的记录数 int page = 1, size = 50; // 构建搜索请求,指定索引为"hotel",从((当前页码-1) * 每页大小)的位置开始获取数据 // 并设置每页获取size条记录,同时按照price字段降序排序 SearchRequest request = SearchRequest.of(b -> b .index("hotel") .from((page - 1) * size) .size(size).sort(s -> s.field(f -> f.field("price").order(SortOrder.Desc))) ); // 使用Elasticsearch客户端执行搜索请求,返回HotelDoc类型的SearchResponse对象 SearchResponse searchResponse = client.search(request, HotelDoc.class); // 处理并解析搜索响应结果 handleResponse(searchResponse); } ``` ### 5.8.高亮 ```java /** * 高亮显示 */ @Test void testHighlight() throws IOException { // 构建搜索请求 SearchRequest request = SearchRequest.of(b -> b .index("hotel") .query(q -> q.match(m -> m.field("all").query("如家"))) .highlight(Highlight.of(o -> o.requireFieldMatch(false).fields("name", t -> t.preTags("").postTags(""))))); // 执行搜索请求 SearchResponse searchResponse = client.search(request, HotelDoc.class); // 处理搜索结果 handleResponse(searchResponse); } ``` ### 5.9.地理位置(geo_distance) - 查询半径范围内数据 ```java @Test void testGeoDistance() throws IOException { // 创建SearchRequest对象 SearchRequest request = SearchRequest.of(b -> b .index("hotel") // 设置索引名称为"hotel" .query(q -> q.geoDistance(g -> g.distance("100km").field("location").location(GeoLocation.of(a -> a.latlon(c -> c.lat(31.21).lon(121.5)))))) // 设置查询条件为距离"location"字段的值为100km的地理位置查询 ); // 执行查询 SearchResponse searchResponse = client.search(request, HotelDoc.class); // 处理查询结果 handleResponse(searchResponse); } ``` - 查询半径数据后排序 ```java /** * 查询全部数据并根据地理位置排序 */ @Test void testGeoDistanceSort() throws IOException { // 创建SearchRequest对象 SearchRequest request = SearchRequest.of(b -> b .index("hotel") // 设置索引名称为"hotel" .sort(s -> s.geoDistance(d -> d.field("location").location(l -> l.latlon(c -> c.lat(31.21).lon(121.5))).order(SortOrder.Asc).unit(DistanceUnit.Kilometers))) // 设置排序方式为根据地理位置排序,按照距离升序排列,单位为千米 ); // 执行搜索请求 SearchResponse searchResponse = client.search(request, HotelDoc.class); // 处理搜索结果 handleResponse(searchResponse); } ``` ### 5.10.算分函数查询 ```java @Test public void testfunctionScore() throws IOException { // 创建SearchRequest对象 SearchRequest request = SearchRequest.of(b -> b // 设置索引名称为"hotel" .index("hotel") // 设置查询方式为算分函数查询,使用match查询匹配字段"all"中包含"外滩"的文档,设置一个过滤器,过滤出id为"434082"的文档,并设置权重为10.0,使用乘法方式计算得分 .query(q -> q.functionScore(f -> f.query(w -> w.match(m -> m.field("all").query("外滩"))).functions(m -> m.filter(s -> s.term(t -> t.field("id").value("434082"))).weight(10.0)).boostMode(FunctionBoostMode.Multiply)))// 设置查询方式为算分函数查询,使用match查询匹配字段"all"中包含"外滩"的文档,设置一个过滤器,过滤出id为"434082"的文档,并设置权重为10.0,使用乘法方式计算得分 ); // 执行搜索请求 SearchResponse searchResponse = client.search(request, HotelDoc.class); // 处理搜索结果 handleResponse(searchResponse); } ``` ### 5.11.公共返回值处理方法 ```java /** * 处理搜索响应 * @param response 搜索响应 */ private void handleResponse(SearchResponse response) { System.out.println("response = " + response); // 4.解析响应 HitsMetadata hitsMetadata = response.hits(); // 4.1.获取总条数 long total = hitsMetadata.total().value(); System.out.println("共搜索到" + total + "条数据"); // 4.2.获取结果集 List> hits = hitsMetadata.hits(); hits.forEach(hit -> { HotelDoc hotelDoc = hit.source(); Map> highlight = hit.highlight(); // 4.2.1.处理高亮显示 if (highlight != null && highlight.containsKey("name")) { List highlightedNames = highlight.get("name"); System.out.println(highlightedNames.get(0)); // 合并原name和高亮片段(这里假设只取第一个高亮片段) hotelDoc.setName(highlightedNames.get(0)); } // 4.2.2.处理排序结果 List sort = hit.sort(); if (sort != null && sort.size() > 0) { // 4.2.1.获取排序字段 FieldValue fieldValue = sort.get(1); // 4.2.2.获取排序值 Object value = fieldValue.doubleValue(); hotelDoc.setDistance(value); } System.out.println(hotelDoc); }); } ``` ## 六、聚合搜索 ### 6.1.bucket聚合 ```java /** * bucket聚合结果排序 */ @Test public void testBucketAggregation() throws IOException { SearchRequest request = SearchRequest.of(a -> a .index("hotel").query(b -> b.range(c -> c.field("price").lte(JsonData.of(200)))).aggregations("brand_agg", d -> d.terms(t -> t.field("brand").size(20).order(NamedValue.of("_count", SortOrder.Asc)))).size(0) ); SearchResponse searchResponse = client.search(request, HotelDoc.class); handleAggResponse(searchResponse); } ``` ### 6.2.Metric聚合 ```java /** * Metric聚合语法测试 */ @Test public void testMetricAggregation() throws IOException { // 构建SearchRequest对象 SearchRequest request = SearchRequest.of(a -> a .index("hotel").aggregations("brand_agg", d -> d.terms(e -> e.field("brand").size(20).order(NamedValue.of("score_agg.avg", SortOrder.Asc))).aggregations("score_agg", s -> s.stats(f -> f.field("score")))).size(0) ); // 执行搜索请求 SearchResponse searchResponse = client.search(request, HotelDoc.class); // 处理聚合响应 handleAggResponse(searchResponse); } ``` ### 6.3.处理聚合响应结果 ```java /** * 处理聚合响应 * * @param searchResponse 搜索响应 */ private void handleAggResponse(SearchResponse searchResponse) { // 打印搜索响应 // System.out.println(searchResponse); // 获取聚合结果 Map aggregations = searchResponse.aggregations(); // 打印聚合结果 // System.out.println(aggregations); // 获取品牌聚合结果 Aggregate brandAgg = aggregations.get("brand_agg"); // 获取品牌聚合结果的字符串聚合结果 StringTermsAggregate stermsAggregate = brandAgg.sterms(); // 获取品牌聚合结果的桶 Buckets buckets = stermsAggregate.buckets(); // 将桶转换为列表 List bucketList = buckets.array(); // 遍历桶列表 bucketList.forEach(bucket -> { // 获取桶的key String key = bucket.key().stringValue(); // 获取桶的docCount long docCount = bucket.docCount(); // 获取桶的聚合结果 Map scoreAgg = bucket.aggregations(); if (scoreAgg.size()>0) { // 获取桶的score聚合结果 Aggregate aggregate = scoreAgg.get("score_agg"); // 获取score聚合结果的统计聚合结果 StatsAggregate statsAggregate = aggregate.stats(); System.out.println("key:" + key + ", docCount:" + docCount + ", score_agg:" + statsAggregate); } // 打印全部参数 System.out.println("key:" + key + ", docCount:" + docCount); }); } ``` ## 七、自动补全 ### 7.1.拼音分词器 [下载地址](https://github.com/medcl/elasticsearch-analysis-pinyin) 解压后重命名放入以下目录 image-20240219112217934 ### 7.2.创建索引 - 在HotelConsts.java中添加以下代码 ```java public static final String INDEX_TEMPLATE = """ { "settings": { "analysis": { "analyzer": { "text_anlyzer": { "tokenizer": "ik_max_word", "filter": "py" }, "completion_analyzer": { "tokenizer": "keyword", "filter": "py" } }, "filter": { "py": { "type": "pinyin", "keep_full_pinyin": false, "keep_joined_full_pinyin": true, "keep_original": true, "limit_first_letter_length": 16, "remove_duplicated_term": true, "none_chinese_pinyin_tokenize": false } } } }, "mappings": { "properties": { "id":{ "type": "keyword" }, "name":{ "type": "text", "analyzer": "text_anlyzer", "search_analyzer": "ik_smart", "copy_to": "all" }, "address":{ "type": "keyword", "index": false }, "price":{ "type": "integer" }, "score":{ "type": "integer" }, "brand":{ "type": "keyword", "copy_to": "all" }, "city":{ "type": "keyword" }, "starName":{ "type": "keyword" }, "business":{ "type": "keyword", "copy_to": "all" }, "location":{ "type": "geo_point" }, "pic":{ "type": "keyword", "index": false }, "all":{ "type": "text", "analyzer": "text_anlyzer", "search_analyzer": "ik_smart" }, "suggestion":{ "type": "completion", "analyzer": "completion_analyzer" } } } } """; ``` - 编写创建索引代码 ```java /** * 创建索引测试方法,该方法读取HotelIndexConsts.INDEX_TEMPLATE中的模板内容, * 并使用其创建一个名为"hotel2"的索引请求。 * * @throws Exception 如果在创建索引过程中出现异常,则抛出异常 */ @Test public void createIndex() throws Exception { // 创建一个从字符串读取器,读取预定义的索引模板内容 Reader reader = new StringReader(HotelIndexConsts.INDEX_TEMPLATE); // 使用读取到的模板内容构建一个CreateIndexRequest对象,指定索引名称为"hotel2" CreateIndexRequest request = CreateIndexRequest.of(a -> a.index("hotel2").withJson(reader)); // 调用Elasticsearch客户端的indices().create()方法发送创建索引请求 CreateIndexResponse response = client.indices().create(request); // 输出响应结果,检查索引是否成功创建(acknowledged字段表示操作是否被集群中所有相关节点确认执行) System.out.println(response.acknowledged()); } ``` - 执行批量导入数据到es ```java //批量导入数据到es @Test void testBulkRequest() throws IOException { // 批量查询酒店数据 List hotels = hotelService.list(); List bulkOperations = new ArrayList<>(); hotels.stream().forEach(hotel -> { HotelDoc hotelDoc = new HotelDoc(hotel); bulkOperations.add(BulkOperation.of(b -> b.index(c -> c.document(hotelDoc).id(hotelDoc.getId().toString())))); }); BulkResponse response = client.bulk(b -> b.index("hotel2").operations(bulkOperations)); response.items().forEach(System.out::println); } ``` ### 7.3.自动补全 ```java /** * 自动补全测试 */ @Test void testSuggest() throws IOException { // 创建搜索请求 SearchRequest searchRequest = SearchRequest.of(a -> a.index("hotel2").suggest(b -> b.suggesters("my_suggest", c -> c.text("h").completion(d -> d.field("suggestion").skipDuplicates(true).size(10)))) ); // 执行搜索请求 SearchResponse searchResponse = client.search(searchRequest, HotelDoc.class); // 处理搜索响应 handleResponse(searchResponse); } ``` ### 7.4.处理响应结果 ```java /** * 处理响应结果 * * @param searchResponse 搜索响应结果 */ private void handleResponse(SearchResponse searchResponse) { // 获取建议结果 Map>> suggestions = searchResponse.suggest(); // 获取指定建议结果 Suggestion suggestion = suggestions.get("my_suggest").getFirst(); // 获取建议结果的选项列表 List> options = suggestion.completion().options(); // 遍历选项列表并打印选项文本 options.forEach(option -> { System.out.println(option.text()); }); } ``` ## 八、实践项目地址 [码云](https://gitee.com/satan1996/elasticsearch-learn.git) [本地knife4j文档地址](http://localhost:8080/doc.html) ![image-20240219114523104](assets/image-20240219114523104.png)