ES 示例和文档

pull/19/head
dunwu 2022-03-01 18:55:46 +08:00
parent 64b6fae5cb
commit 793a841ee1
14 changed files with 798 additions and 245 deletions

View File

@ -77,6 +77,7 @@
- [Elasticsearch 快速入门](docs/nosql/elasticsearch/Elasticsearch快速入门.md)
- [Elasticsearch 简介](docs/nosql/elasticsearch/Elasticsearch简介.md)
- [Elasticsearch Rest API](docs/nosql/elasticsearch/ElasticsearchRestApi.md)
- [ElasticSearch Java API 之 High Level REST Client](docs/nosql/elasticsearch/ElasticsearchHighLevelRestJavaApi.md)
- [Elasticsearch 索引管理](docs/nosql/elasticsearch/Elasticsearch索引管理.md)
- [Elasticsearch 查询](docs/nosql/elasticsearch/Elasticsearch查询.md)
- [Elasticsearch 高亮](docs/nosql/elasticsearch/Elasticsearch高亮.md)

View File

@ -4,6 +4,8 @@ import lombok.Data;
import lombok.ToString;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
@Data
@ToString
@ -11,12 +13,16 @@ import org.springframework.data.elasticsearch.annotations.Document;
public class Product {
@Id
@Field(type = FieldType.Keyword)
private String id;
@Field(type = FieldType.Keyword)
private String name;
@Field(type = FieldType.Text)
private String description;
@Field(type = FieldType.Boolean)
private boolean enabled;
public Product(String id, String name, String description, boolean enabled) {

View File

@ -1,18 +1,26 @@
package io.github.dunwu.javadb.elasticsearch.springboot;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.json.JSONUtil;
import io.github.dunwu.javadb.elasticsearch.springboot.entities.Product;
import io.github.dunwu.javadb.elasticsearch.springboot.entities.User;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
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.support.master.AcknowledgedResponse;
import org.elasticsearch.client.GetAliasesResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.cluster.metadata.AliasMetadata;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xcontent.XContentType;
import org.junit.jupiter.api.*;
@ -20,8 +28,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:forbreak@163.com">Zhang Peng</a>
@ -30,76 +36,18 @@ import java.util.Set;
@SpringBootTest
public class RestHighLevelClientDocumentApiTest {
public static final String INDEX = "mytest";
public static final String INDEX_ALIAS = "mytest_alias";
/**
* {@link User} mapping json
*/
public static final String MAPPING_JSON = "{\n"
+ " \"properties\": {\n"
+ " \"age\": {\n"
+ " \"type\": \"long\"\n"
+ " },\n"
+ " \"desc\": {\n"
+ " \"type\": \"text\",\n"
+ " \"fields\": {\n"
+ " \"keyword\": {\n"
+ " \"type\": \"keyword\",\n"
+ " \"ignore_above\": 256\n"
+ " }\n"
+ " }\n"
+ " },\n"
+ " \"email\": {\n"
+ " \"type\": \"text\",\n"
+ " \"fielddata\": true\n"
+ " },\n"
+ " \"id\": {\n"
+ " \"type\": \"text\",\n"
+ " \"fields\": {\n"
+ " \"keyword\": {\n"
+ " \"type\": \"keyword\",\n"
+ " \"ignore_above\": 256\n"
+ " }\n"
+ " }\n"
+ " },\n"
+ " \"password\": {\n"
+ " \"type\": \"text\",\n"
+ " \"fields\": {\n"
+ " \"keyword\": {\n"
+ " \"type\": \"keyword\",\n"
+ " \"ignore_above\": 256\n"
+ " }\n"
+ " }\n"
+ " },\n"
+ " \"title\": {\n"
+ " \"type\": \"text\",\n"
+ " \"fields\": {\n"
+ " \"keyword\": {\n"
+ " \"type\": \"keyword\",\n"
+ " \"ignore_above\": 256\n"
+ " }\n"
+ " }\n"
+ " },\n"
+ " \"user\": {\n"
+ " \"type\": \"text\",\n"
+ " \"fields\": {\n"
+ " \"keyword\": {\n"
+ " \"type\": \"keyword\",\n"
+ " \"ignore_above\": 256\n"
+ " }\n"
+ " }\n"
+ " },\n"
+ " \"username\": {\n"
+ " \"type\": \"text\",\n"
+ " \"fields\": {\n"
+ " \"keyword\": {\n"
+ " \"type\": \"keyword\",\n"
+ " \"ignore_above\": 256\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}";
public static final String MAPPING_JSON =
"{\n" + " \"properties\": {\n" + " \"_class\": {\n" + " \"type\": \"keyword\",\n"
+ " \"index\": false,\n" + " \"doc_values\": false\n" + " },\n" + " \"description\": {\n"
+ " \"type\": \"text\",\n" + " \"fielddata\": true\n" + " },\n" + " \"enabled\": {\n"
+ " \"type\": \"boolean\"\n" + " },\n" + " \"name\": {\n" + " \"type\": \"text\",\n"
+ " \"fielddata\": true\n" + " }\n" + " }\n" + "}";
@Autowired
private RestHighLevelClient client;
@ -111,10 +59,8 @@ public class RestHighLevelClientDocumentApiTest {
CreateIndexRequest createIndexRequest = new CreateIndexRequest(INDEX);
// 设置索引的 settings
createIndexRequest.settings(Settings.builder()
.put("index.number_of_shards", 3)
.put("index.number_of_replicas", 2)
);
createIndexRequest.settings(
Settings.builder().put("index.number_of_shards", 3).put("index.number_of_replicas", 2));
// 设置索引的 mapping
createIndexRequest.mapping(MAPPING_JSON, XContentType.JSON);
@ -122,8 +68,7 @@ public class RestHighLevelClientDocumentApiTest {
// 设置索引的别名
createIndexRequest.alias(new Alias(INDEX_ALIAS));
AcknowledgedResponse response =
client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
AcknowledgedResponse response = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
Assertions.assertTrue(response.isAcknowledged());
// 判断索引是否存在
@ -142,29 +87,142 @@ public class RestHighLevelClientDocumentApiTest {
}
@Test
@DisplayName("列出所有索引")
public void listAllIndex() throws IOException {
GetAliasesRequest request = new GetAliasesRequest();
GetAliasesResponse getAliasesResponse = client.indices().getAlias(request, RequestOptions.DEFAULT);
Map<String, Set<AliasMetadata>> map = getAliasesResponse.getAliases();
Set<String> indices = map.keySet();
indices.forEach(System.out::println);
@DisplayName("同步新建文档")
public void index() throws IOException {
IndexRequest request = new IndexRequest(INDEX_ALIAS);
request.id("1");
Product product = new Product();
product.setName("机器人");
product.setDescription("人工智能机器人");
product.setEnabled(true);
String jsonString = JSONUtil.toJsonStr(product);
request.source(jsonString, XContentType.JSON);
// 同步执行
IndexResponse response = client.index(request, RequestOptions.DEFAULT);
System.out.println(response);
}
@Test
public void method() throws IOException {
IndexRequest request = new IndexRequest(INDEX);
request.id("1");
String jsonString = "{\n"
+ " \"id\": \"1\",\n"
+ " \"userName\": \"Jack\",\n"
+ " \"age\": 12,\n"
+ " \"password\": \"123456\",\n"
+ " \"email\": \"jack@xxx.com\"\n"
+ "}";
@DisplayName("异步新建文档")
public void indexAsync() {
IndexRequest request = new IndexRequest(INDEX_ALIAS);
Product product = new Product();
product.setName("机器人");
product.setDescription("人工智能机器人");
product.setEnabled(true);
String jsonString = JSONUtil.toJsonStr(product);
request.source(jsonString, XContentType.JSON);
IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT);
System.out.println("indexResponse: " + indexResponse.getResult());
// 异步执行
client.indexAsync(request, RequestOptions.DEFAULT, new ActionListener<IndexResponse>() {
@Override
public void onResponse(IndexResponse indexResponse) {
System.out.println(indexResponse);
}
@Override
public void onFailure(Exception e) {
System.out.println("执行失败");
}
});
}
@Test
@DisplayName("删除文档")
public void delete() throws IOException {
// 创建文档请求
IndexRequest request = new IndexRequest(INDEX_ALIAS);
request.id("1");
Product product = new Product();
product.setName("机器人");
product.setDescription("人工智能机器人");
product.setEnabled(true);
String jsonString = JSONUtil.toJsonStr(product);
request.source(jsonString, XContentType.JSON);
// 同步执行创建操作
IndexResponse response = client.index(request, RequestOptions.DEFAULT);
System.out.println(response);
// 删除文档请求
DeleteRequest deleteRequest = new DeleteRequest(INDEX_ALIAS, "1");
// 同步执行删除操作
// DeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);
// System.out.println(deleteResponse);
// 异步执行删除操作
client.deleteAsync(deleteRequest, RequestOptions.DEFAULT, new ActionListener<DeleteResponse>() {
@Override
public void onResponse(DeleteResponse deleteResponse) {
System.out.println(deleteResponse);
}
@Override
public void onFailure(Exception e) {
System.out.println("执行失败");
}
});
}
@Test
@DisplayName("更新文档")
public void update() throws IOException {
// 创建文档请求
IndexRequest request = new IndexRequest(INDEX_ALIAS);
request.id("1");
Product product = new Product();
product.setName("机器人");
product.setDescription("人工智能机器人");
product.setEnabled(true);
String jsonString = JSONUtil.toJsonStr(product);
request.source(jsonString, XContentType.JSON);
// 同步执行创建操作
IndexResponse response = client.index(request, RequestOptions.DEFAULT);
System.out.println(response);
// 查询文档操作
GetRequest getRequest = new GetRequest(INDEX_ALIAS, "1");
GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
Product product2 = BeanUtil.mapToBean(getResponse.getSource(), Product.class, true, CopyOptions.create());
System.out.println("product2: " + product2);
Assertions.assertEquals(product.getName(), product2.getName());
// 更新文档请求
UpdateRequest updateRequest = new UpdateRequest(INDEX_ALIAS, "1");
Product product3 = new Product();
product3.setName("扫地机器人");
product3.setDescription("人工智能扫地机器人");
product3.setEnabled(true);
String jsonString2 = JSONUtil.toJsonStr(product3);
updateRequest.doc(jsonString2, XContentType.JSON);
// 同步执行更新操作
UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT);
System.out.println(updateResponse);
// 异步执行更新操作
// client.updateAsync(updateRequest, RequestOptions.DEFAULT, new ActionListener<UpdateResponse>() {
// @Override
// public void onResponse(UpdateResponse updateResponse) {
// System.out.println(updateResponse);
// }
//
// @Override
// public void onFailure(Exception e) {
// System.out.println("执行失败");
// }
// });
// 查询文档操作
GetResponse getResponse2 = client.get(getRequest, RequestOptions.DEFAULT);
Product product4 = BeanUtil.mapToBean(getResponse2.getSource(), Product.class, true, CopyOptions.create());
System.out.println("product4: " + product4);
Assertions.assertEquals(product3.getName(), product4.getName());
}
}

View File

@ -0,0 +1,97 @@
package io.github.dunwu.javadb.elasticsearch.springboot;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import io.github.dunwu.javadb.elasticsearch.springboot.entity.ecommerce.KibanaSampleDataEcommerceBean;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
/**
* @author <a href="mailto:forbreak@163.com">Zhang Peng</a>
* @date 2022-03-01
*/
@SpringBootTest
public class RestHighLevelClientDocumentSearchApiTest {
public static final String INDEX = "kibana_sample_data_ecommerce";
@Autowired
private RestHighLevelClient client;
@Test
@DisplayName("获取匹配条件的记录总数")
public void count() throws IOException {
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchPhraseQuery("customer_gender", "MALE"));
sourceBuilder.trackTotalHits(true);
CountRequest countRequest = new CountRequest(INDEX);
countRequest.source(sourceBuilder);
CountResponse countResponse = client.count(countRequest, RequestOptions.DEFAULT);
long count = countResponse.getCount();
System.out.println("命中记录数:" + count);
}
@ParameterizedTest
@ValueSource(ints = {0, 1, 2, 3})
@DisplayName("分页查询测试")
public void pageTest(int page) throws IOException {
int size = 10;
int offset = page * size;
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchPhraseQuery("customer_gender", "MALE"));
sourceBuilder.from(offset);
sourceBuilder.size(size);
sourceBuilder.trackTotalHits(true);
SearchRequest searchRequest = new SearchRequest(INDEX);
searchRequest.source(sourceBuilder);
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHit[] hits = response.getHits().getHits();
for (SearchHit hit : hits) {
KibanaSampleDataEcommerceBean bean =
BeanUtil.mapToBean(hit.getSourceAsMap(), KibanaSampleDataEcommerceBean.class, true,
CopyOptions.create());
System.out.println(bean);
}
}
@Test
@DisplayName("条件查询")
public void matchPhraseQuery() throws IOException {
SearchRequest searchRequest = new SearchRequest(INDEX);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("customer_last_name", "Jensen"));
sourceBuilder.query(boolQueryBuilder);
sourceBuilder.trackTotalHits(true);
searchRequest.source(sourceBuilder);
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHit[] hits = response.getHits().getHits();
for (SearchHit hit : hits) {
KibanaSampleDataEcommerceBean bean =
BeanUtil.mapToBean(hit.getSourceAsMap(), KibanaSampleDataEcommerceBean.class, true,
CopyOptions.create());
System.out.println(bean);
}
}
}

View File

@ -4,7 +4,6 @@ import io.github.dunwu.javadb.elasticsearch.springboot.entities.User;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.GetAliasesResponse;
import org.elasticsearch.client.RequestOptions;
@ -36,74 +35,15 @@ public class RestHighLevelClientIndexApiTest {
/**
* {@link User} mapping json
*/
public static final String MAPPING_JSON = "{\n"
+ " \"properties\": {\n"
+ " \"age\": {\n"
+ " \"type\": \"long\"\n"
+ " },\n"
+ " \"desc\": {\n"
+ " \"type\": \"text\",\n"
+ " \"fields\": {\n"
+ " \"keyword\": {\n"
+ " \"type\": \"keyword\",\n"
+ " \"ignore_above\": 256\n"
+ " }\n"
+ " }\n"
+ " },\n"
+ " \"email\": {\n"
+ " \"type\": \"text\",\n"
+ " \"fielddata\": true\n"
+ " },\n"
+ " \"id\": {\n"
+ " \"type\": \"text\",\n"
+ " \"fields\": {\n"
+ " \"keyword\": {\n"
+ " \"type\": \"keyword\",\n"
+ " \"ignore_above\": 256\n"
+ " }\n"
+ " }\n"
+ " },\n"
+ " \"password\": {\n"
+ " \"type\": \"text\",\n"
+ " \"fields\": {\n"
+ " \"keyword\": {\n"
+ " \"type\": \"keyword\",\n"
+ " \"ignore_above\": 256\n"
+ " }\n"
+ " }\n"
+ " },\n"
+ " \"title\": {\n"
+ " \"type\": \"text\",\n"
+ " \"fields\": {\n"
+ " \"keyword\": {\n"
+ " \"type\": \"keyword\",\n"
+ " \"ignore_above\": 256\n"
+ " }\n"
+ " }\n"
+ " },\n"
+ " \"user\": {\n"
+ " \"type\": \"text\",\n"
+ " \"fields\": {\n"
+ " \"keyword\": {\n"
+ " \"type\": \"keyword\",\n"
+ " \"ignore_above\": 256\n"
+ " }\n"
+ " }\n"
+ " },\n"
+ " \"username\": {\n"
+ " \"type\": \"text\",\n"
+ " \"fields\": {\n"
+ " \"keyword\": {\n"
+ " \"type\": \"keyword\",\n"
+ " \"ignore_above\": 256\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}";
public static final String MAPPING_JSON =
"{\n" + " \"properties\": {\n" + " \"_class\": {\n" + " \"type\": \"keyword\",\n"
+ " \"index\": false,\n" + " \"doc_values\": false\n" + " },\n" + " \"description\": {\n"
+ " \"type\": \"text\",\n" + " \"fielddata\": true\n" + " },\n" + " \"enabled\": {\n"
+ " \"type\": \"boolean\"\n" + " },\n" + " \"name\": {\n" + " \"type\": \"text\",\n"
+ " \"fielddata\": true\n" + " }\n" + " }\n" + "}";
@Autowired
private RestHighLevelClient restHighLevelClient;
private RestHighLevelClient client;
@Test
@DisplayName("创建、删除索引测试")
@ -113,10 +53,8 @@ public class RestHighLevelClientIndexApiTest {
CreateIndexRequest createIndexRequest = new CreateIndexRequest(INDEX);
// 设置索引的 settings
createIndexRequest.settings(Settings.builder()
.put("index.number_of_shards", 3)
.put("index.number_of_replicas", 2)
);
createIndexRequest.settings(
Settings.builder().put("index.number_of_shards", 3).put("index.number_of_replicas", 2));
// 设置索引的 mapping
createIndexRequest.mapping(MAPPING_JSON, XContentType.JSON);
@ -124,41 +62,34 @@ public class RestHighLevelClientIndexApiTest {
// 设置索引的别名
createIndexRequest.alias(new Alias(INDEX_ALIAS));
AcknowledgedResponse response =
restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
Assertions.assertTrue(response.isAcknowledged());
AcknowledgedResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
Assertions.assertTrue(createIndexResponse.isAcknowledged());
// 判断索引是否存在
GetIndexRequest getIndexRequest = new GetIndexRequest(INDEX);
Assertions.assertTrue(restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT));
Assertions.assertTrue(client.indices().exists(getIndexRequest, RequestOptions.DEFAULT));
GetIndexRequest getIndexAliasRequest = new GetIndexRequest(INDEX_ALIAS);
Assertions.assertTrue(restHighLevelClient.indices().exists(getIndexAliasRequest, RequestOptions.DEFAULT));
Assertions.assertTrue(client.indices().exists(getIndexAliasRequest, RequestOptions.DEFAULT));
// 删除索引
DeleteIndexRequest request = new DeleteIndexRequest(INDEX);
response = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
Assertions.assertTrue(response.isAcknowledged());
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(INDEX);
AcknowledgedResponse deleteResponse = client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
Assertions.assertTrue(deleteResponse.isAcknowledged());
// 判断索引是否存在
Assertions.assertFalse(client.indices().exists(getIndexRequest, RequestOptions.DEFAULT));
Assertions.assertFalse(client.indices().exists(getIndexAliasRequest, RequestOptions.DEFAULT));
}
@Test
@DisplayName("列出所有索引")
public void listAllIndex() throws IOException {
GetAliasesRequest request = new GetAliasesRequest();
GetAliasesResponse getAliasesResponse = restHighLevelClient.indices().getAlias(request, RequestOptions.DEFAULT);
GetAliasesResponse getAliasesResponse = client.indices().getAlias(request, RequestOptions.DEFAULT);
Map<String, Set<AliasMetadata>> map = getAliasesResponse.getAliases();
Set<String> indices = map.keySet();
indices.forEach(System.out::println);
}
public void method() {
IndexRequest request = new IndexRequest("posts");
request.id("1");
String jsonString = "{" +
"\"user\":\"kimchy\"," +
"\"postDate\":\"2013-01-30\"," +
"\"message\":\"trying out Elasticsearch\"" +
"}";
request.source(jsonString, XContentType.JSON);
}
}

View File

@ -0,0 +1,12 @@
package io.github.dunwu.javadb.elasticsearch.springboot.entity.ecommerce;
import lombok.Data;
@Data
public class Geoip {
private String continentName;
private String cityName;
private String countryIsoCode;
private Location location;
private String regionName;
}

View File

@ -0,0 +1,32 @@
package io.github.dunwu.javadb.elasticsearch.springboot.entity.ecommerce;
import lombok.Data;
import java.util.List;
@Data
public class KibanaSampleDataEcommerceBean {
private Geoip geoip;
private String customerFirstName;
private String customerPhone;
private String type;
private List<String> manufacturer;
private List<ProductsItem> products;
private String customerFullName;
private String orderDate;
private String customerLastName;
private int dayOfWeekI;
private int totalQuantity;
private String currency;
private double taxlessTotalPrice;
private int totalUniqueProducts;
private List<String> category;
private int customerId;
private List<String> sku;
private int orderId;
private String user;
private String customerGender;
private String email;
private String dayOfWeek;
private double taxfulTotalPrice;
}

View File

@ -0,0 +1,9 @@
package io.github.dunwu.javadb.elasticsearch.springboot.entity.ecommerce;
import lombok.Data;
@Data
public class Location {
private int lon;
private double lat;
}

View File

@ -0,0 +1,25 @@
package io.github.dunwu.javadb.elasticsearch.springboot.entity.ecommerce;
import lombok.Data;
@Data
public class ProductsItem {
private int taxAmount;
private double taxfulPrice;
private int quantity;
private double taxlessPrice;
private int discountAmount;
private double baseUnitPrice;
private int discountPercentage;
private String productName;
private String manufacturer;
private double minPrice;
private String createdOn;
private int unitDiscountAmount;
private double price;
private int productId;
private double basePrice;
private String id;
private String category;
private String sku;
}

View File

@ -76,6 +76,7 @@ footer: CC-BY-SA-4.0 Licensed | Copyright © 2018-Now Dunwu
- [Elasticsearch 快速入门](nosql/elasticsearch/Elasticsearch快速入门.md)
- [Elasticsearch 简介](nosql/elasticsearch/Elasticsearch简介.md)
- [Elasticsearch Rest API](nosql/elasticsearch/ElasticsearchRestApi.md)
- [ElasticSearch Java API 之 High Level REST Client](nosql/elasticsearch/ElasticsearchHighLevelRestJavaApi.md)
- [Elasticsearch 索引管理](nosql/elasticsearch/Elasticsearch索引管理.md)
- [Elasticsearch 查询](nosql/elasticsearch/Elasticsearch查询.md)
- [Elasticsearch 高亮](nosql/elasticsearch/Elasticsearch高亮.md)

View File

@ -4,27 +4,37 @@
### 列式数据库
- [HBase](hbase.md)
#### [HBase](hbase.md)
### K-V 数据库
- [Redis](redis/README.md)
- [Cassandra](cassandra.md)
#### [Redis](redis/README.md)
#### [Cassandra](cassandra.md)
### 文档数据库
- [MongoDB](mongodb)
#### [MongoDB](mongodb)
### 搜索引擎数据库
> [Elasticsearch](elasticsearch) 📚
#### [Elasticsearch](elasticsearch) 📚
> Elasticsearch 是一个基于 Lucene 的搜索和数据分析工具它提供了一个分布式服务。Elasticsearch 是遵从 Apache 开源条款的一款开源产品,是当前主流的企业级搜索引擎。
- [Elasticsearch 面试总结](elasticsearch/elasticsearch-interview.md) 💯
- [Elasticsearch 简介](elasticsearch/Elasticsearch简介.md)
- [Elasticsearch 快速入门](elasticsearch/Elasticsearch快速入门.md)
- [Elasticsearch 基本概念](elasticsearch/Elasticsearch索引管理.md)
- [Elasticsearch 简介](elasticsearch/Elasticsearch简介.md)
- [Elasticsearch Rest API](elasticsearch/ElasticsearchRestApi.md)
- [ElasticSearch Java API 之 High Level REST Client](elasticsearch/ElasticsearchHighLevelRestJavaApi.md)
- [Elasticsearch 索引管理](elasticsearch/Elasticsearch索引管理.md)
- [Elasticsearch 查询](elasticsearch/Elasticsearch查询.md)
- [Elasticsearch 高亮](elasticsearch/Elasticsearch高亮.md)
- [Elasticsearch 排序](elasticsearch/Elasticsearch排序.md)
- [Elasticsearch 聚合](elasticsearch/Elasticsearch聚合.md)
- [Elasticsearch 分析器](elasticsearch/Elasticsearch分析器.md)
- [Elasticsearch 运维](elasticsearch/Elasticsearch运维.md)
- [Elasticsearch 性能优化](elasticsearch/Elasticsearch性能优化.md)
### 图数据库
@ -32,6 +42,23 @@ TODO: 待补充
## 📚 资料
### Mysql 资料
- **官方**
- [Mysql 官网](https://www.mysql.com/)
- [Mysql 官方文档](https://dev.mysql.com/doc/refman/8.0/en/)
- [Mysql 官方文档之命令行客户端](https://dev.mysql.com/doc/refman/8.0/en/mysql.html)
- **书籍**
- [《高性能 MySQL》](https://book.douban.com/subject/23008813/) - 经典,适合 DBA 或作为开发者的参考手册
- [《MySQL 必知必会》](https://book.douban.com/subject/3354490/) - 适合入门者
- **教程**
- [runoob.com MySQL 教程](http://www.runoob.com/mysql/mysql-tutorial.html) - 入门级 SQL 教程
- [mysql-tutorial](https://github.com/jaywcjlove/mysql-tutorial)
- **更多资源**
- [awesome-mysql](https://github.com/jobbole/awesome-mysql-cn)
### Redis 资料
- **官网**
- [Redis 官网](https://redis.io/)
- [Redis github](https://github.com/antirez/redis)
@ -40,7 +67,7 @@ TODO: 待补充
- **书籍**
- [《Redis 实战》](https://item.jd.com/11791607.html)
- [《Redis 设计与实现》](https://item.jd.com/11486101.html)
- 源码
- **源码**
- [《Redis 实战》配套 Python 源码](https://github.com/josiahcarlson/redis-in-action)
- **资源汇总**
- [awesome-redis](https://github.com/JamzyWang/awesome-redis)
@ -51,6 +78,20 @@ TODO: 待补充
- [CRUG | Redisson PRO vs. Jedis: Which Is Faster? 翻译](https://www.jianshu.com/p/82f0d5abb002)
- [redis 分布锁 Redisson 性能测试](https://blog.csdn.net/everlasting_188/article/details/51073505)
### MongoDB 资料
- **官方**
- [MongoDB 官网](https://www.mongodb.com/)
- [MongoDB Github](https://github.com/mongodb/mongo)
- [MongoDB 官方免费教程](https://university.mongodb.com/)
- **教程**
- [MongoDB 教程](https://www.runoob.com/mongodb/mongodb-tutorial.html)
- [MongoDB 高手课](https://time.geekbang.org/course/intro/100040001)
- **数据**
- [mongodb-json-files](https://github.com/ozlerhakan/mongodb-json-files)
- **文章**
- [Introduction to MongoDB](https://www.slideshare.net/mdirolf/introduction-to-mongodb)
## 🚪 传送
◾ 🏠 [DB-TUTORIAL 首页](https://github.com/dunwu/db-tutorial) ◾ 🎯 [我的博客](https://github.com/dunwu/blog) ◾

View File

@ -0,0 +1,389 @@
# ElasticSearch Java API 之 High Level REST Client
> Elasticsearch 官方的 High Level REST Client 在 7.1.5.0 版本废弃。所以本文中的 API 不推荐使用。
<!-- TOC depthFrom:2 depthTo:3 -->
- [1. 快速开始](#1-快速开始)
- [1.1. 引入依赖](#11-引入依赖)
- [1.2. 创建连接和关闭](#12-创建连接和关闭)
- [2. 索引 API](#2-索引-api)
- [2.1. 测试准备](#21-测试准备)
- [2.2. 创建索引](#22-创建索引)
- [2.3. 删除索引](#23-删除索引)
- [2.4. 判断索引是否存在](#24-判断索引是否存在)
- [3. 文档 API](#3-文档-api)
- [3.1. 文档测试准备](#31-文档测试准备)
- [3.2. 创建文档](#32-创建文档)
- [3.3. 删除文档](#33-删除文档)
- [3.4. 更新文档](#34-更新文档)
- [3.5. 查看文档](#35-查看文档)
- [3.6. 获取匹配条件的记录总数](#36-获取匹配条件的记录总数)
- [3.7. 分页查询](#37-分页查询)
- [3.8. 条件查询](#38-条件查询)
- [4. 参考资料](#4-参考资料)
<!-- /TOC -->
## 1. 快速开始
### 1.1. 引入依赖
在 pom.xml 中引入以下依赖:
```xml
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.17.1</version>
</dependency>
```
### 1.2. 创建连接和关闭
```java
// 创建连接
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("localhost", 9200, "http"),
new HttpHost("localhost", 9201, "http")));
// 关闭
client.close();
```
## 2. 索引 API
### 2.1. 测试准备
```java
public static final String INDEX = "mytest";
public static final String INDEX_ALIAS = "mytest_alias";
/**
* {@link User} 的 mapping 结构json形式
*/
public static final String MAPPING_JSON =
"{\n" + " \"properties\": {\n" + " \"_class\": {\n" + " \"type\": \"keyword\",\n"
+ " \"index\": false,\n" + " \"doc_values\": false\n" + " },\n" + " \"description\": {\n"
+ " \"type\": \"text\",\n" + " \"fielddata\": true\n" + " },\n" + " \"enabled\": {\n"
+ " \"type\": \"boolean\"\n" + " },\n" + " \"name\": {\n" + " \"type\": \"text\",\n"
+ " \"fielddata\": true\n" + " }\n" + " }\n" + "}";
@Autowired
private RestHighLevelClient client;
```
### 2.2. 创建索引
```java
// 创建索引
CreateIndexRequest createIndexRequest = new CreateIndexRequest(INDEX);
// 设置索引的 settings
createIndexRequest.settings(
Settings.builder().put("index.number_of_shards", 3).put("index.number_of_replicas", 2));
// 设置索引的 mapping
createIndexRequest.mapping(MAPPING_JSON, XContentType.JSON);
// 设置索引的别名
createIndexRequest.alias(new Alias(INDEX_ALIAS));
AcknowledgedResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
Assertions.assertTrue(createIndexResponse.isAcknowledged());
```
### 2.3. 删除索引
```java
// 删除索引
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(INDEX);
AcknowledgedResponse deleteResponse = client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
Assertions.assertTrue(deleteResponse.isAcknowledged());
```
### 2.4. 判断索引是否存在
```java
GetIndexRequest getIndexRequest = new GetIndexRequest(INDEX);
Assertions.assertTrue(client.indices().exists(getIndexRequest, RequestOptions.DEFAULT));
GetIndexRequest getIndexAliasRequest = new GetIndexRequest(INDEX_ALIAS);
Assertions.assertTrue(client.indices().exists(getIndexAliasRequest, RequestOptions.DEFAULT));
```
## 3. 文档 API
### 3.1. 文档测试准备
```java
public static final String INDEX = "mytest";
public static final String INDEX_ALIAS = "mytest_alias";
/**
* {@link User} 的 mapping 结构json形式
*/
public static final String MAPPING_JSON =
"{\n" + " \"properties\": {\n" + " \"_class\": {\n" + " \"type\": \"keyword\",\n"
+ " \"index\": false,\n" + " \"doc_values\": false\n" + " },\n" + " \"description\": {\n"
+ " \"type\": \"text\",\n" + " \"fielddata\": true\n" + " },\n" + " \"enabled\": {\n"
+ " \"type\": \"boolean\"\n" + " },\n" + " \"name\": {\n" + " \"type\": \"text\",\n"
+ " \"fielddata\": true\n" + " }\n" + " }\n" + "}";
@Autowired
private RestHighLevelClient client;
@BeforeEach
public void init() throws IOException {
// 创建索引
CreateIndexRequest createIndexRequest = new CreateIndexRequest(INDEX);
// 设置索引的 settings
createIndexRequest.settings(
Settings.builder().put("index.number_of_shards", 3).put("index.number_of_replicas", 2));
// 设置索引的 mapping
createIndexRequest.mapping(MAPPING_JSON, XContentType.JSON);
// 设置索引的别名
createIndexRequest.alias(new Alias(INDEX_ALIAS));
AcknowledgedResponse response = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
Assertions.assertTrue(response.isAcknowledged());
// 判断索引是否存在
GetIndexRequest getIndexRequest = new GetIndexRequest(INDEX_ALIAS);
Assertions.assertTrue(client.indices().exists(getIndexRequest, RequestOptions.DEFAULT));
GetIndexRequest getIndexAliasRequest = new GetIndexRequest(INDEX_ALIAS);
Assertions.assertTrue(client.indices().exists(getIndexAliasRequest, RequestOptions.DEFAULT));
}
@AfterEach
public void destroy() throws IOException {
// 删除索引
DeleteIndexRequest request = new DeleteIndexRequest(INDEX);
AcknowledgedResponse response = client.indices().delete(request, RequestOptions.DEFAULT);
Assertions.assertTrue(response.isAcknowledged());
}
```
### 3.2. 创建文档
RestHighLevelClient Api 使用 `IndexRequest` 来构建创建文档的请求参数。
【示例】创建 id 为 1 的文档
```java
IndexRequest request = new IndexRequest("product");
request.id("1");
Product product = new Product();
product.setName("机器人");
product.setDescription("人工智能机器人");
product.setEnabled(true);
String jsonString = JSONUtil.toJsonStr(product);
request.source(jsonString, XContentType.JSON);
```
同步执行
```java
IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT);
```
异步执行
```java
// 异步执行
client.indexAsync(request, RequestOptions.DEFAULT, new ActionListener<IndexResponse>() {
@Override
public void onResponse(IndexResponse indexResponse) {
System.out.println(indexResponse);
}
@Override
public void onFailure(Exception e) {
System.out.println("执行失败");
}
});
```
### 3.3. 删除文档
RestHighLevelClient Api 使用 `DeleteRequest` 来构建删除文档的请求参数。
【示例】删除 id 为 1 的文档
```java
DeleteRequest deleteRequest = new DeleteRequest(INDEX_ALIAS, "1");
```
同步执行
```java
DeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);
System.out.println(deleteResponse);
```
异步执行
```java
client.deleteAsync(deleteRequest, RequestOptions.DEFAULT, new ActionListener<DeleteResponse>() {
@Override
public void onResponse(DeleteResponse deleteResponse) {
System.out.println(deleteResponse);
}
@Override
public void onFailure(Exception e) {
System.out.println("执行失败");
}
});
```
### 3.4. 更新文档
RestHighLevelClient Api 使用 `UpdateRequest` 来构建更新文档的请求参数。
【示例】更新 id 为 1 的文档
```java
UpdateRequest updateRequest = new UpdateRequest(INDEX_ALIAS, "1");
Product product3 = new Product();
product3.setName("扫地机器人");
product3.setDescription("人工智能扫地机器人");
product3.setEnabled(true);
String jsonString2 = JSONUtil.toJsonStr(product3);
updateRequest.doc(jsonString2, XContentType.JSON);
```
同步执行
```java
UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT);
System.out.println(updateResponse);
```
异步执行
```java
client.updateAsync(updateRequest, RequestOptions.DEFAULT, new ActionListener<UpdateResponse>() {
@Override
public void onResponse(UpdateResponse updateResponse) {
System.out.println(updateResponse);
}
@Override
public void onFailure(Exception e) {
System.out.println("执行失败");
}
});
```
### 3.5. 查看文档
RestHighLevelClient Api 使用 `GetRequest` 来构建查看文档的请求参数。
【示例】查看 id 为 1 的文档
```java
GetRequest getRequest = new GetRequest(INDEX_ALIAS, "1");
```
同步执行
```java
GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
```
异步执行
```java
client.getAsync(getRequest, RequestOptions.DEFAULT, new ActionListener<GetResponse>() {
@Override
public void onResponse(GetResponse getResponse) {
System.out.println(getResponse);
}
@Override
public void onFailure(Exception e) {
System.out.println("执行失败");
}
});
```
### 3.6. 获取匹配条件的记录总数
```java
@Test
@DisplayName("获取匹配条件的记录总数")
public void count() throws IOException {
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchPhraseQuery("customer_gender", "MALE"));
sourceBuilder.trackTotalHits(true);
CountRequest countRequest = new CountRequest(INDEX);
countRequest.source(sourceBuilder);
CountResponse countResponse = client.count(countRequest, RequestOptions.DEFAULT);
long count = countResponse.getCount();
System.out.println("命中记录数:" + count);
}
```
### 3.7. 分页查询
```java
@ParameterizedTest
@ValueSource(ints = {0, 1, 2, 3})
@DisplayName("分页查询测试")
public void pageTest(int page) throws IOException {
int size = 10;
int offset = page * size;
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchPhraseQuery("customer_gender", "MALE"));
sourceBuilder.from(offset);
sourceBuilder.size(size);
sourceBuilder.trackTotalHits(true);
SearchRequest searchRequest = new SearchRequest(INDEX);
searchRequest.source(sourceBuilder);
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHit[] hits = response.getHits().getHits();
for (SearchHit hit : hits) {
KibanaSampleDataEcommerceBean bean =
BeanUtil.mapToBean(hit.getSourceAsMap(), KibanaSampleDataEcommerceBean.class, true,
CopyOptions.create());
System.out.println(bean);
}
}
```
### 3.8. 条件查询
```java
@Test
@DisplayName("条件查询")
public void matchPhraseQuery() throws IOException {
SearchRequest searchRequest = new SearchRequest(INDEX);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("customer_last_name", "Jensen"));
sourceBuilder.query(boolQueryBuilder);
sourceBuilder.trackTotalHits(true);
searchRequest.source(sourceBuilder);
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHit[] hits = response.getHits().getHits();
for (SearchHit hit : hits) {
KibanaSampleDataEcommerceBean bean =
BeanUtil.mapToBean(hit.getSourceAsMap(), KibanaSampleDataEcommerceBean.class, true,
CopyOptions.create());
System.out.println(bean);
}
}
```
## 4. 参考资料
- **官方**
- [Java High Level REST Client](https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html)

View File

@ -1,51 +0,0 @@
# ElasticSearch Java API
> **[Elasticsearch](https://github.com/elastic/elasticsearch) 是一个分布式、RESTful 风格的搜索和数据分析引擎**,能够解决不断涌现出的各种用例。 作为 Elastic Stack 的核心,它集中存储您的数据,帮助您发现意料之中以及意料之外的情况。
>
> [Elasticsearch](https://github.com/elastic/elasticsearch) 基于搜索库 [Lucene](https://github.com/apache/lucene-solr) 开发。ElasticSearch 隐藏了 Lucene 的复杂性,提供了简单易用的 REST API / Java API 接口(另外还有其他语言的 API 接口)。
>
> _以下简称 ES_
>
> REST API 最详尽的文档应该参考:[ES 官方 REST API](https://www.elastic.co/guide/en/elasticsearch/reference/current/rest-apis.html)
<!-- TOC depthFrom:2 depthTo:3 -->
- [1. ElasticSearch Rest API 语法格式](#1-elasticsearch-rest-api-语法格式)
- [2. 索引 API](#2-索引-api)
- [2.1. 创建索引](#21-创建索引)
- [2.2. 删除索引](#22-删除索引)
- [2.3. 查看索引](#23-查看索引)
- [2.4. 索引别名](#24-索引别名)
- [2.5. 打开/关闭索引](#25-打开关闭索引)
- [3. 文档](#3-文档)
- [3.1. 创建文档](#31-创建文档)
- [3.2. 删除文档](#32-删除文档)
- [3.3. 更新文档](#33-更新文档)
- [3.4. 查询文档](#34-查询文档)
- [3.5. 全文搜索](#35-全文搜索)
- [3.6. 逻辑运算](#36-逻辑运算)
- [3.7. 批量执行](#37-批量执行)
- [3.8. 批量读取](#38-批量读取)
- [3.9. 批量查询](#39-批量查询)
- [3.10. URI Search 查询语义](#310-uri-search-查询语义)
- [3.11. Request Body & DSL](#311-request-body--dsl)
- [4. 集群 API](#4-集群-api)
- [4.1. 集群健康 API](#41-集群健康-api)
- [4.2. 集群状态 API](#42-集群状态-api)
- [5. 节点 API](#5-节点-api)
- [6. 分片 API](#6-分片-api)
- [7. 监控 API](#7-监控-api)
- [8. 参考资料](#8-参考资料)
<!-- /TOC -->
## 索引 API
- [Create Index API](https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-create-index.html)
- [Delete Index API](https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-delete-index.html)
- [Index Exists API](https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-indices-exists.html)
## 8. 参考资料
- **官方**
- [Java High Level REST Client](https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html)

View File

@ -12,6 +12,8 @@
### [Elasticsearch Rest API](ElasticsearchRestApi.md)
### [ElasticSearch Java API 之 High Level REST Client](ElasticsearchHighLevelRestJavaApi.md)
### [Elasticsearch 索引管理](Elasticsearch索引管理.md)
### [Elasticsearch 查询](Elasticsearch查询.md)