@@ -0,0 +1,25 @@ | |||||
/target/ | |||||
!.mvn/wrapper/maven-wrapper.jar | |||||
### STS ### | |||||
.apt_generated | |||||
.classpath | |||||
.factorypath | |||||
.project | |||||
.settings | |||||
.springBeans | |||||
.sts4-cache | |||||
### IntelliJ IDEA ### | |||||
.idea | |||||
*.iws | |||||
*.iml | |||||
*.ipr | |||||
### NetBeans ### | |||||
/nbproject/private/ | |||||
/build/ | |||||
/nbbuild/ | |||||
/dist/ | |||||
/nbdist/ | |||||
/.nb-gradle/ |
@@ -0,0 +1,473 @@ | |||||
# spring-boot-demo-elasticsearch-rest-high-level-client | |||||
> 此 demo 主要演示了 Spring Boot 如何集成 `elasticsearch-rest-high-level-client` 完成对 ElasticSearch 的基本CURD 操作 | |||||
## elasticsearch 升级 | |||||
先升级到 6.8,索引创建,设置 mapping 等操作加参数:include_type_name=true,然后滚动升级到 7,旧索引可以用 type 访问。具体可以参考: | |||||
https://www.elastic.co/cn/blog/moving-from-types-to-typeless-apis-in-elasticsearch-7-0 | |||||
https://www.elastic.co/guide/en/elasticsearch/reference/7.0/removal-of-types.html | |||||
## 注意 | |||||
作者编写本demo时,ElasticSearch版本为 `7.3.0`,使用 docker 运行,下面是所有步骤: | |||||
1. 下载镜像:`docker pull elasticsearch:7.3.0` | |||||
2. 下载安装 `docker-compose` | |||||
``` | |||||
sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose | |||||
参考文档: https://docs.docker.com/compose/install/ | |||||
``` | |||||
2. 编写docker-compose 文件 | |||||
```yaml | |||||
version: "3" | |||||
services: | |||||
es7: | |||||
hostname: es7 | |||||
container_name: es7 | |||||
image: elasticsearch:7.3.0 | |||||
volumes: | |||||
- "/data/es7/logs:/usr/share/es7/logs:rw" | |||||
- "/data/es7/data:/usr/share/es7/data:rw" | |||||
restart: on-failure | |||||
ports: | |||||
- "9200:9200" | |||||
- "9300:9300" | |||||
environment: | |||||
cluster.name: elasticsearch | |||||
discovery.type: single-node | |||||
logging: | |||||
driver: "json-file" | |||||
options: | |||||
max-size: "50m" | |||||
``` | |||||
3. 启动: `docker-compose -f elasticsearch.yaml up -d` | |||||
## pom.xml | |||||
```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.0</modelVersion> | |||||
<parent> | |||||
<artifactId>spring-boot-demo</artifactId> | |||||
<groupId>com.xkcoding</groupId> | |||||
<version>1.0.0-SNAPSHOT</version> | |||||
</parent> | |||||
<artifactId>spring-boot-demo-elasticsearch-rest-high-level-client</artifactId> | |||||
<name>spring-boot-demo-elasticsearch-rest-high-level-client</name> | |||||
<description>Demo project for Spring Boot</description> | |||||
<properties> | |||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | |||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> | |||||
<java.version>1.8</java.version> | |||||
</properties> | |||||
<dependencies> | |||||
<dependency> | |||||
<groupId>org.springframework.boot</groupId> | |||||
<artifactId>spring-boot-starter</artifactId> | |||||
</dependency> | |||||
<!-- test --> | |||||
<dependency> | |||||
<groupId>org.springframework.boot</groupId> | |||||
<artifactId>spring-boot-starter-test</artifactId> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<!-- validator --> | |||||
<dependency> | |||||
<groupId>org.hibernate.validator</groupId> | |||||
<artifactId>hibernate-validator</artifactId> | |||||
<scope>compile</scope> | |||||
</dependency> | |||||
<!-- | |||||
You can easily generate your own configuration metadata file from items annotated with | |||||
@ConfigurationProperties by using the spring-boot-configuration-processor jar. | |||||
--> | |||||
<dependency> | |||||
<groupId>org.springframework.boot</groupId> | |||||
<artifactId>spring-boot-configuration-processor</artifactId> | |||||
</dependency> | |||||
<!-- 工具类 --> | |||||
<dependency> | |||||
<groupId>cn.hutool</groupId> | |||||
<artifactId>hutool-all</artifactId> | |||||
<version>4.6.6</version> | |||||
</dependency> | |||||
<!-- elasticsearch --> | |||||
<dependency> | |||||
<groupId>org.elasticsearch</groupId> | |||||
<artifactId>elasticsearch</artifactId> | |||||
<version>7.3.0</version> | |||||
</dependency> | |||||
<!-- elasticsearch-rest-client --> | |||||
<dependency> | |||||
<groupId>org.elasticsearch.client</groupId> | |||||
<artifactId>elasticsearch-rest-client</artifactId> | |||||
<version>7.3.0</version> | |||||
</dependency> | |||||
<!-- elasticsearch-rest-high-level-client --> | |||||
<dependency> | |||||
<groupId>org.elasticsearch.client</groupId> | |||||
<artifactId>elasticsearch-rest-high-level-client</artifactId> | |||||
<version>7.3.0</version> | |||||
<exclusions> | |||||
<exclusion> | |||||
<groupId>org.elasticsearch.client</groupId> | |||||
<artifactId>elasticsearch-rest-client</artifactId> | |||||
</exclusion> | |||||
<exclusion> | |||||
<groupId>org.elasticsearch</groupId> | |||||
<artifactId>elasticsearch</artifactId> | |||||
</exclusion> | |||||
</exclusions> | |||||
</dependency> | |||||
<!-- lombok --> | |||||
<dependency> | |||||
<groupId>org.projectlombok</groupId> | |||||
<artifactId>lombok</artifactId> | |||||
<optional>true</optional> | |||||
</dependency> | |||||
</dependencies> | |||||
</project> | |||||
``` | |||||
## Person.java | |||||
> 实体类 | |||||
> | |||||
```java | |||||
package com.xkcoding.elasticsearch.model; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import java.io.Serializable; | |||||
import java.util.Date; | |||||
/** | |||||
* Person | |||||
* | |||||
* @author fxbin | |||||
* @version v1.0 | |||||
* @since 2019/9/15 23:04 | |||||
*/ | |||||
@Data | |||||
@Builder | |||||
@NoArgsConstructor | |||||
@AllArgsConstructor | |||||
public class Person implements Serializable { | |||||
private static final long serialVersionUID = 8510634155374943623L; | |||||
/** | |||||
* 主键 | |||||
*/ | |||||
private Long id; | |||||
/** | |||||
* 名字 | |||||
*/ | |||||
private String name; | |||||
/** | |||||
* 国家 | |||||
*/ | |||||
private String country; | |||||
/** | |||||
* 年龄 | |||||
*/ | |||||
private Integer age; | |||||
/** | |||||
* 生日 | |||||
*/ | |||||
private Date birthday; | |||||
/** | |||||
* 介绍 | |||||
*/ | |||||
private String remark; | |||||
} | |||||
``` | |||||
## PersonService.java | |||||
```java | |||||
package com.xkcoding.elasticsearch.service; | |||||
import com.xkcoding.elasticsearch.model.Person; | |||||
import org.springframework.lang.Nullable; | |||||
import java.util.List; | |||||
/** | |||||
* PersonService | |||||
* | |||||
* @author fxbin | |||||
* @version v1.0 | |||||
* @since 2019/9/15 23:07 | |||||
*/ | |||||
public interface PersonService { | |||||
/** | |||||
* create Index | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index name | |||||
*/ | |||||
void createIndex(String index); | |||||
/** | |||||
* delete Index | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index name | |||||
*/ | |||||
void deleteIndex(String index); | |||||
/** | |||||
* insert document source | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index name | |||||
* @param list data source | |||||
*/ | |||||
void insert(String index, List<Person> list); | |||||
/** | |||||
* update document source | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index name | |||||
* @param list data source | |||||
*/ | |||||
void update(String index, List<Person> list); | |||||
/** | |||||
* delete document source | |||||
* | |||||
* @author fxbin | |||||
* @param person delete data source and allow null object | |||||
*/ | |||||
void delete(String index, @Nullable Person person); | |||||
/** | |||||
* search all doc records | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index name | |||||
* @return person list | |||||
*/ | |||||
List<Person> searchList(String index); | |||||
} | |||||
``` | |||||
## PersonServiceImpl.java | |||||
> service 实现类型,基本CURD操作 | |||||
```java | |||||
package com.xkcoding.elasticsearch.service.impl; | |||||
import cn.hutool.core.bean.BeanUtil; | |||||
import com.xkcoding.elasticsearch.model.Person; | |||||
import com.xkcoding.elasticsearch.service.BaseElasticsearchService; | |||||
import com.xkcoding.elasticsearch.service.PersonService; | |||||
import org.elasticsearch.action.index.IndexRequest; | |||||
import org.elasticsearch.action.search.SearchResponse; | |||||
import org.elasticsearch.search.SearchHit; | |||||
import org.springframework.stereotype.Service; | |||||
import org.springframework.util.ObjectUtils; | |||||
import java.io.IOException; | |||||
import java.util.ArrayList; | |||||
import java.util.Arrays; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
/** | |||||
* PersonServiceImpl | |||||
* | |||||
* @author fxbin | |||||
* @version v1.0 | |||||
* @since 2019/9/15 23:08 | |||||
*/ | |||||
@Service | |||||
public class PersonServiceImpl extends BaseElasticsearchService implements PersonService { | |||||
@Override | |||||
public void createIndex(String index) { | |||||
createIndexRequest(index); | |||||
} | |||||
@Override | |||||
public void deleteIndex(String index) { | |||||
deleteIndexRequest(index); | |||||
} | |||||
@Override | |||||
public void insert(String index, List<Person> list) { | |||||
try { | |||||
list.forEach(person -> { | |||||
IndexRequest request = buildIndexRequest(index, String.valueOf(person.getId()), person); | |||||
try { | |||||
client.index(request, COMMON_OPTIONS); | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
}); | |||||
} finally { | |||||
try { | |||||
client.close(); | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
} | |||||
@Override | |||||
public void update(String index, List<Person> list) { | |||||
list.forEach(person -> { | |||||
updateRequest(index, String.valueOf(person.getId()), person); | |||||
}); | |||||
} | |||||
@Override | |||||
public void delete(String index, Person person) { | |||||
if (ObjectUtils.isEmpty(person)) { | |||||
// 如果person 对象为空,则删除全量 | |||||
searchList(index).forEach(p -> { | |||||
deleteRequest(index, String.valueOf(p.getId())); | |||||
}); | |||||
} | |||||
deleteRequest(index, String.valueOf(person.getId())); | |||||
} | |||||
@Override | |||||
public List<Person> searchList(String index) { | |||||
SearchResponse searchResponse = search(index); | |||||
SearchHit[] hits = searchResponse.getHits().getHits(); | |||||
List<Person> personList = new ArrayList<>(); | |||||
Arrays.stream(hits).forEach(hit -> { | |||||
Map<String, Object> sourceAsMap = hit.getSourceAsMap(); | |||||
Person person = BeanUtil.mapToBean(sourceAsMap, Person.class, true); | |||||
personList.add(person); | |||||
}); | |||||
return personList; | |||||
} | |||||
} | |||||
``` | |||||
## ElasticsearchApplicationTests.java | |||||
> 主要功能测试,参见service 注释说明 | |||||
```java | |||||
package com.xkcoding.elasticsearch; | |||||
import com.xkcoding.elasticsearch.contants.ElasticsearchConstant; | |||||
import com.xkcoding.elasticsearch.model.Person; | |||||
import com.xkcoding.elasticsearch.service.PersonService; | |||||
import org.junit.Test; | |||||
import org.junit.runner.RunWith; | |||||
import org.springframework.boot.test.context.SpringBootTest; | |||||
import org.springframework.test.context.junit4.SpringRunner; | |||||
import javax.annotation.Resource; | |||||
import java.util.ArrayList; | |||||
import java.util.Date; | |||||
import java.util.List; | |||||
@RunWith(SpringRunner.class) | |||||
@SpringBootTest | |||||
public class ElasticsearchApplicationTests { | |||||
@Resource | |||||
private PersonService personService; | |||||
@Test | |||||
public void deleteIndexTest() { | |||||
personService.deleteIndex(ElasticsearchConstant.INDEX_NAME); | |||||
} | |||||
@Test | |||||
public void createIndexTest() { | |||||
personService.createIndex(ElasticsearchConstant.INDEX_NAME); | |||||
} | |||||
@Test | |||||
public void insertTest() { | |||||
List<Person> list = new ArrayList<>(); | |||||
list.add(Person.builder().age(11).birthday(new Date()).country("CN").id(1L).name("哈哈").remark("test1").build()); | |||||
list.add(Person.builder().age(22).birthday(new Date()).country("US").id(2L).name("hiahia").remark("test2").build()); | |||||
list.add(Person.builder().age(33).birthday(new Date()).country("ID").id(3L).name("呵呵").remark("test3").build()); | |||||
personService.insert(ElasticsearchConstant.INDEX_NAME, list); | |||||
} | |||||
@Test | |||||
public void updateTest() { | |||||
Person person = Person.builder().age(33).birthday(new Date()).country("ID_update").id(3L).name("呵呵update").remark("test3_update").build(); | |||||
List<Person> list = new ArrayList<>(); | |||||
list.add(person); | |||||
personService.update(ElasticsearchConstant.INDEX_NAME, list); | |||||
} | |||||
@Test | |||||
public void deleteTest() { | |||||
personService.delete(ElasticsearchConstant.INDEX_NAME, Person.builder().id(1L).build()); | |||||
} | |||||
@Test | |||||
public void searchListTest() { | |||||
List<Person> personList = personService.searchList(ElasticsearchConstant.INDEX_NAME); | |||||
System.out.println(personList); | |||||
} | |||||
} | |||||
``` | |||||
## 参考 | |||||
1. ElasticSearch 官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html | |||||
2. Java High Level REST Client:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.3/java-rest-high.html | |||||
@@ -49,6 +49,13 @@ | |||||
<artifactId>spring-boot-configuration-processor</artifactId> | <artifactId>spring-boot-configuration-processor</artifactId> | ||||
</dependency> | </dependency> | ||||
<!-- 工具类 --> | |||||
<dependency> | |||||
<groupId>cn.hutool</groupId> | |||||
<artifactId>hutool-all</artifactId> | |||||
<version>4.6.6</version> | |||||
</dependency> | |||||
<!-- elasticsearch --> | <!-- elasticsearch --> | ||||
<dependency> | <dependency> | ||||
<groupId>org.elasticsearch</groupId> | <groupId>org.elasticsearch</groupId> | ||||
@@ -56,16 +63,23 @@ | |||||
<version>7.3.0</version> | <version>7.3.0</version> | ||||
</dependency> | </dependency> | ||||
<!-- elasticsearch-rest-client --> | |||||
<dependency> | |||||
<groupId>org.elasticsearch.client</groupId> | |||||
<artifactId>elasticsearch-rest-client</artifactId> | |||||
<version>7.3.0</version> | |||||
</dependency> | |||||
<!-- elasticsearch-rest-high-level-client --> | <!-- elasticsearch-rest-high-level-client --> | ||||
<dependency> | <dependency> | ||||
<groupId>org.elasticsearch.client</groupId> | <groupId>org.elasticsearch.client</groupId> | ||||
<artifactId>elasticsearch-rest-high-level-client</artifactId> | <artifactId>elasticsearch-rest-high-level-client</artifactId> | ||||
<version>7.3.0</version> | <version>7.3.0</version> | ||||
<exclusions> | <exclusions> | ||||
<!-- <exclusion>--> | |||||
<!-- <groupId>org.elasticsearch.client</groupId>--> | |||||
<!-- <artifactId>elasticsearch-rest-client</artifactId>--> | |||||
<!-- </exclusion>--> | |||||
<exclusion> | |||||
<groupId>org.elasticsearch.client</groupId> | |||||
<artifactId>elasticsearch-rest-client</artifactId> | |||||
</exclusion> | |||||
<exclusion> | <exclusion> | ||||
<groupId>org.elasticsearch</groupId> | <groupId>org.elasticsearch</groupId> | ||||
<artifactId>elasticsearch</artifactId> | <artifactId>elasticsearch</artifactId> | ||||
@@ -1,4 +1,4 @@ | |||||
package com.xlcoding.elasticsearch; | |||||
package com.xkcoding.elasticsearch; | |||||
import org.springframework.boot.SpringApplication; | import org.springframework.boot.SpringApplication; | ||||
import org.springframework.boot.autoconfigure.SpringBootApplication; | import org.springframework.boot.autoconfigure.SpringBootApplication; |
@@ -1,6 +1,10 @@ | |||||
package com.xlcoding.elasticsearch.autoconfigure; | |||||
package com.xkcoding.elasticsearch.autoconfigure; | |||||
import org.apache.http.HttpHost; | import org.apache.http.HttpHost; | ||||
import org.apache.http.auth.AuthScope; | |||||
import org.apache.http.auth.UsernamePasswordCredentials; | |||||
import org.apache.http.client.CredentialsProvider; | |||||
import org.apache.http.impl.client.BasicCredentialsProvider; | |||||
import org.elasticsearch.client.RestClient; | import org.elasticsearch.client.RestClient; | ||||
import org.elasticsearch.client.RestClientBuilder; | import org.elasticsearch.client.RestClientBuilder; | ||||
import org.elasticsearch.client.RestHighLevelClient; | import org.elasticsearch.client.RestHighLevelClient; | ||||
@@ -78,6 +82,15 @@ public class ElasticsearchAutoConfiguration { | |||||
httpClientBuilder.setMaxConnPerRoute(elasticsearchProperties.getMaxConnectPerRoute()); | httpClientBuilder.setMaxConnPerRoute(elasticsearchProperties.getMaxConnectPerRoute()); | ||||
return httpClientBuilder; | return httpClientBuilder; | ||||
}); | }); | ||||
// Callback used the basic credential auth | |||||
ElasticsearchProperties.Account account = elasticsearchProperties.getAccount(); | |||||
if (!StringUtils.isEmpty(account.getUsername()) && !StringUtils.isEmpty(account.getUsername())) { | |||||
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); | |||||
credentialsProvider.setCredentials(AuthScope.ANY, | |||||
new UsernamePasswordCredentials(account.getUsername(), account.getPassword())); | |||||
} | |||||
return new RestHighLevelClient(builder); | return new RestHighLevelClient(builder); | ||||
} | } | ||||
@@ -1,9 +1,6 @@ | |||||
package com.xlcoding.elasticsearch.autoconfigure; | |||||
package com.xkcoding.elasticsearch.autoconfigure; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import lombok.*; | |||||
import org.springframework.boot.context.properties.ConfigurationProperties; | import org.springframework.boot.context.properties.ConfigurationProperties; | ||||
import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
@@ -70,21 +67,40 @@ public class ElasticsearchProperties { | |||||
/** | /** | ||||
* 索引配置信息 | * 索引配置信息 | ||||
*/ | */ | ||||
private Index index; | |||||
private Index index = new Index(); | |||||
/** | |||||
* 认证账户 | |||||
*/ | |||||
private Account account = new Account(); | |||||
@Data | @Data | ||||
@Builder | |||||
public static class Index { | public static class Index { | ||||
/** | /** | ||||
* 分片数量 | * 分片数量 | ||||
*/ | */ | ||||
protected Integer numberOfShards = 3; | |||||
private Integer numberOfShards = 3; | |||||
/** | /** | ||||
* 副本数量 | * 副本数量 | ||||
*/ | */ | ||||
protected Integer numberOfReplicas = 2; | |||||
private Integer numberOfReplicas = 2; | |||||
} | |||||
@Data | |||||
public static class Account { | |||||
/** | |||||
* 认证用户 | |||||
*/ | |||||
private String username; | |||||
/** | |||||
* 认证密码 | |||||
*/ | |||||
private String password; | |||||
} | } | ||||
@@ -1,4 +1,4 @@ | |||||
package com.xlcoding.elasticsearch.contants; | |||||
package com.xkcoding.elasticsearch.contants; | |||||
/** | /** | ||||
* DataTypeTransfer | * DataTypeTransfer |
@@ -1,4 +1,4 @@ | |||||
package com.xlcoding.elasticsearch.contants; | |||||
package com.xkcoding.elasticsearch.contants; | |||||
/** | /** | ||||
* ElasticsearchConstant | * ElasticsearchConstant |
@@ -1,6 +1,6 @@ | |||||
package com.xlcoding.elasticsearch.exception; | |||||
package com.xkcoding.elasticsearch.exception; | |||||
import com.xlcoding.elasticsearch.model.ResultCode; | |||||
import com.xkcoding.elasticsearch.model.ResultCode; | |||||
import lombok.Getter; | import lombok.Getter; | ||||
/** | /** |
@@ -1,4 +1,4 @@ | |||||
package com.xlcoding.elasticsearch.model; | |||||
package com.xkcoding.elasticsearch.model; | |||||
import lombok.AllArgsConstructor; | import lombok.AllArgsConstructor; | ||||
import lombok.Builder; | import lombok.Builder; |
@@ -1,4 +1,4 @@ | |||||
package com.xlcoding.elasticsearch.model; | |||||
package com.xkcoding.elasticsearch.model; | |||||
import lombok.Data; | import lombok.Data; | ||||
import org.springframework.lang.Nullable; | import org.springframework.lang.Nullable; |
@@ -1,4 +1,4 @@ | |||||
package com.xlcoding.elasticsearch.model; | |||||
package com.xkcoding.elasticsearch.model; | |||||
import lombok.AllArgsConstructor; | import lombok.AllArgsConstructor; | ||||
import lombok.Getter; | import lombok.Getter; |
@@ -0,0 +1,170 @@ | |||||
package com.xkcoding.elasticsearch.service; | |||||
import com.xkcoding.elasticsearch.exception.ElasticsearchException; | |||||
import com.xkcoding.elasticsearch.autoconfigure.ElasticsearchProperties; | |||||
import com.xkcoding.elasticsearch.util.BeanUtils; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.elasticsearch.action.ActionListener; | |||||
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; | |||||
import org.elasticsearch.action.delete.DeleteRequest; | |||||
import org.elasticsearch.action.index.IndexRequest; | |||||
import org.elasticsearch.action.search.SearchRequest; | |||||
import org.elasticsearch.action.search.SearchResponse; | |||||
import org.elasticsearch.action.update.UpdateRequest; | |||||
import org.elasticsearch.action.update.UpdateResponse; | |||||
import org.elasticsearch.client.HttpAsyncResponseConsumerFactory; | |||||
import org.elasticsearch.client.RequestOptions; | |||||
import org.elasticsearch.client.RestHighLevelClient; | |||||
import org.elasticsearch.client.indices.CreateIndexRequest; | |||||
import org.elasticsearch.client.indices.CreateIndexResponse; | |||||
import org.elasticsearch.common.settings.Settings; | |||||
import org.elasticsearch.common.xcontent.XContentType; | |||||
import org.elasticsearch.index.engine.Engine; | |||||
import org.elasticsearch.index.query.QueryBuilders; | |||||
import org.elasticsearch.search.builder.SearchSourceBuilder; | |||||
import javax.annotation.Resource; | |||||
import java.io.IOException; | |||||
/** | |||||
* BaseElasticsearchService | |||||
* | |||||
* @author fxbin | |||||
* @version 1.0v | |||||
* @since 2019/9/16 15:44 | |||||
*/ | |||||
@Slf4j | |||||
public abstract class BaseElasticsearchService { | |||||
@Resource | |||||
protected RestHighLevelClient client; | |||||
@Resource | |||||
private ElasticsearchProperties elasticsearchProperties; | |||||
protected static final RequestOptions COMMON_OPTIONS; | |||||
static { | |||||
RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder(); | |||||
// 默认缓冲限制为100MB,此处修改为30MB。 | |||||
builder.setHttpAsyncResponseConsumerFactory( | |||||
new HttpAsyncResponseConsumerFactory | |||||
.HeapBufferedResponseConsumerFactory(30 * 1024 * 1024)); | |||||
COMMON_OPTIONS = builder.build(); | |||||
} | |||||
/** | |||||
* create elasticsearch index (asyc) | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index | |||||
*/ | |||||
protected void createIndexRequest(String index) { | |||||
try { | |||||
CreateIndexRequest request = new CreateIndexRequest(index); | |||||
// Settings for this index | |||||
request.settings(Settings.builder() | |||||
.put("index.number_of_shards", elasticsearchProperties.getIndex().getNumberOfShards()) | |||||
.put("index.number_of_replicas", elasticsearchProperties.getIndex().getNumberOfReplicas())); | |||||
CreateIndexResponse createIndexResponse = client.indices().create(request, COMMON_OPTIONS); | |||||
log.info(" whether all of the nodes have acknowledged the request : {}", createIndexResponse.isAcknowledged()); | |||||
log.info(" Indicates whether the requisite number of shard copies were started for each shard in the index before timing out :{}", | |||||
createIndexResponse.isShardsAcknowledged()); | |||||
} catch (IOException e) { | |||||
throw new ElasticsearchException("创建索引 {" + index + "} 失败"); | |||||
} | |||||
} | |||||
/** | |||||
* delete elasticsearch index | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index name | |||||
*/ | |||||
protected void deleteIndexRequest(String index) { | |||||
DeleteIndexRequest deleteIndexRequest = buildDeleteIndexRequest(index); | |||||
try { | |||||
client.indices().delete(deleteIndexRequest, COMMON_OPTIONS); | |||||
} catch (IOException e) { | |||||
throw new ElasticsearchException("删除索引 {" + index + "} 失败"); | |||||
} | |||||
} | |||||
/** | |||||
* build DeleteIndexRequest | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index name | |||||
*/ | |||||
private static DeleteIndexRequest buildDeleteIndexRequest (String index) { | |||||
return new DeleteIndexRequest(index); | |||||
} | |||||
/** | |||||
* build IndexRequest | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index name | |||||
* @param id request object id | |||||
* @param object request object | |||||
* @return {@link org.elasticsearch.action.index.IndexRequest} | |||||
*/ | |||||
protected static IndexRequest buildIndexRequest(String index, String id, Object object) { | |||||
return new IndexRequest(index).id(id).source(BeanUtils.toMap(object), XContentType.JSON); | |||||
} | |||||
/** | |||||
* exec updateRequest | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index name | |||||
* @param id Document id | |||||
* @param object request object | |||||
*/ | |||||
protected void updateRequest(String index, String id, Object object) { | |||||
try { | |||||
UpdateRequest updateRequest = new UpdateRequest(index, id).doc(BeanUtils.toMap(object), XContentType.JSON); | |||||
client.update(updateRequest, COMMON_OPTIONS); | |||||
} catch (IOException e) { | |||||
throw new ElasticsearchException("更新索引 {" + index + "} 数据 {" + object + "} 失败"); | |||||
} | |||||
} | |||||
/** | |||||
* exec deleteRequest | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index name | |||||
* @param id Document id | |||||
*/ | |||||
protected void deleteRequest(String index, String id) { | |||||
try { | |||||
DeleteRequest deleteRequest = new DeleteRequest(index, id); | |||||
client.delete(deleteRequest, COMMON_OPTIONS); | |||||
} catch (IOException e) { | |||||
throw new ElasticsearchException("删除索引 {" + index + "} 数据id {" + id + "} 失败"); | |||||
} | |||||
} | |||||
/** | |||||
* search all | |||||
* @param index elasticsearch index name | |||||
* @return {@link SearchResponse} | |||||
*/ | |||||
protected SearchResponse search(String index) { | |||||
SearchRequest searchRequest = new SearchRequest(index); | |||||
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); | |||||
searchSourceBuilder.query(QueryBuilders.matchAllQuery()); | |||||
searchRequest.source(searchSourceBuilder); | |||||
SearchResponse searchResponse = null; | |||||
try { | |||||
searchResponse = client.search(searchRequest, COMMON_OPTIONS); | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
return searchResponse; | |||||
} | |||||
} |
@@ -0,0 +1,68 @@ | |||||
package com.xkcoding.elasticsearch.service; | |||||
import com.xkcoding.elasticsearch.model.Person; | |||||
import org.springframework.lang.Nullable; | |||||
import java.util.List; | |||||
/** | |||||
* PersonService | |||||
* | |||||
* @author fxbin | |||||
* @version v1.0 | |||||
* @since 2019/9/15 23:07 | |||||
*/ | |||||
public interface PersonService { | |||||
/** | |||||
* create Index | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index name | |||||
*/ | |||||
void createIndex(String index); | |||||
/** | |||||
* delete Index | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index name | |||||
*/ | |||||
void deleteIndex(String index); | |||||
/** | |||||
* insert document source | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index name | |||||
* @param list data source | |||||
*/ | |||||
void insert(String index, List<Person> list); | |||||
/** | |||||
* update document source | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index name | |||||
* @param list data source | |||||
*/ | |||||
void update(String index, List<Person> list); | |||||
/** | |||||
* delete document source | |||||
* | |||||
* @author fxbin | |||||
* @param person delete data source and allow null object | |||||
*/ | |||||
void delete(String index, @Nullable Person person); | |||||
/** | |||||
* search all doc records | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index name | |||||
* @return person list | |||||
*/ | |||||
List<Person> searchList(String index); | |||||
} |
@@ -0,0 +1,91 @@ | |||||
package com.xkcoding.elasticsearch.service.impl; | |||||
import cn.hutool.core.bean.BeanUtil; | |||||
import com.xkcoding.elasticsearch.model.Person; | |||||
import com.xkcoding.elasticsearch.service.BaseElasticsearchService; | |||||
import com.xkcoding.elasticsearch.service.PersonService; | |||||
import org.elasticsearch.action.index.IndexRequest; | |||||
import org.elasticsearch.action.search.SearchResponse; | |||||
import org.elasticsearch.search.SearchHit; | |||||
import org.springframework.stereotype.Service; | |||||
import org.springframework.util.ObjectUtils; | |||||
import java.io.IOException; | |||||
import java.util.ArrayList; | |||||
import java.util.Arrays; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
/** | |||||
* PersonServiceImpl | |||||
* | |||||
* @author fxbin | |||||
* @version v1.0 | |||||
* @since 2019/9/15 23:08 | |||||
*/ | |||||
@Service | |||||
public class PersonServiceImpl extends BaseElasticsearchService implements PersonService { | |||||
@Override | |||||
public void createIndex(String index) { | |||||
createIndexRequest(index); | |||||
} | |||||
@Override | |||||
public void deleteIndex(String index) { | |||||
deleteIndexRequest(index); | |||||
} | |||||
@Override | |||||
public void insert(String index, List<Person> list) { | |||||
try { | |||||
list.forEach(person -> { | |||||
IndexRequest request = buildIndexRequest(index, String.valueOf(person.getId()), person); | |||||
try { | |||||
client.index(request, COMMON_OPTIONS); | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
}); | |||||
} finally { | |||||
try { | |||||
client.close(); | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
} | |||||
@Override | |||||
public void update(String index, List<Person> list) { | |||||
list.forEach(person -> { | |||||
updateRequest(index, String.valueOf(person.getId()), person); | |||||
}); | |||||
} | |||||
@Override | |||||
public void delete(String index, Person person) { | |||||
if (ObjectUtils.isEmpty(person)) { | |||||
// 如果person 对象为空,则删除全量 | |||||
searchList(index).forEach(p -> { | |||||
deleteRequest(index, String.valueOf(p.getId())); | |||||
}); | |||||
} | |||||
deleteRequest(index, String.valueOf(person.getId())); | |||||
} | |||||
@Override | |||||
public List<Person> searchList(String index) { | |||||
SearchResponse searchResponse = search(index); | |||||
SearchHit[] hits = searchResponse.getHits().getHits(); | |||||
List<Person> personList = new ArrayList<>(); | |||||
Arrays.stream(hits).forEach(hit -> { | |||||
Map<String, Object> sourceAsMap = hit.getSourceAsMap(); | |||||
Person person = BeanUtil.mapToBean(sourceAsMap, Person.class, true); | |||||
personList.add(person); | |||||
}); | |||||
return personList; | |||||
} | |||||
} |
@@ -1,12 +1,10 @@ | |||||
package com.xlcoding.elasticsearch.util; | |||||
package com.xkcoding.elasticsearch.util; | |||||
import com.xlcoding.elasticsearch.model.Person; | |||||
import com.xkcoding.elasticsearch.model.Person; | |||||
import java.beans.BeanInfo; | import java.beans.BeanInfo; | ||||
import java.beans.IntrospectionException; | |||||
import java.beans.Introspector; | import java.beans.Introspector; | ||||
import java.beans.PropertyDescriptor; | import java.beans.PropertyDescriptor; | ||||
import java.lang.reflect.InvocationTargetException; | |||||
import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||
import java.util.Map; | import java.util.Map; | ||||
@@ -50,15 +48,34 @@ public class BeanUtils { | |||||
return map; | return map; | ||||
} | } | ||||
/** | |||||
* Java Bean to Map | |||||
* | |||||
* @author fxbin | |||||
* @param object Object | |||||
* @return Map | |||||
*/ | |||||
public static Map<String,Object> toMap(Object object){ | |||||
Map<String, Object> map = MapUtils.newHashMap(); | |||||
try { | |||||
// 获取javaBean的BeanInfo对象 | |||||
BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass(),Object.class); | |||||
public static void main(String[] args) { | |||||
Person person = new Person(); | |||||
Map<String, Object> stringObjectMap = toFieldNameAndFieldTypeMap(person); | |||||
System.out.println(stringObjectMap); | |||||
// 获取属性描述器 | |||||
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); | |||||
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { | |||||
// 获取属性名 | |||||
String key = propertyDescriptor.getName(); | |||||
// 获取该属性的值 | |||||
Method readMethod = propertyDescriptor.getReadMethod(); | |||||
// 通过反射来调用javaBean定义的getName()方法 | |||||
Object value = readMethod.invoke(object); | |||||
map.put(key, value); | |||||
} | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
return map; | |||||
} | } | ||||
} | } |
@@ -1,4 +1,4 @@ | |||||
package com.xlcoding.elasticsearch.util; | |||||
package com.xkcoding.elasticsearch.util; | |||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.LinkedHashMap; | import java.util.LinkedHashMap; |
@@ -1,88 +0,0 @@ | |||||
package com.xlcoding.elasticsearch.service; | |||||
import com.xlcoding.elasticsearch.autoconfigure.ElasticsearchProperties; | |||||
import com.xlcoding.elasticsearch.exception.ElasticsearchException; | |||||
import com.xlcoding.elasticsearch.model.Person; | |||||
import com.xlcoding.elasticsearch.util.BeanUtils; | |||||
import com.xlcoding.elasticsearch.util.MapUtils; | |||||
import org.elasticsearch.action.index.IndexRequest; | |||||
import org.elasticsearch.client.indices.CreateIndexRequest; | |||||
import org.elasticsearch.common.settings.Settings; | |||||
import org.elasticsearch.common.xcontent.XContentBuilder; | |||||
import org.elasticsearch.common.xcontent.XContentFactory; | |||||
import javax.annotation.Resource; | |||||
import java.io.IOException; | |||||
import java.util.Map; | |||||
/** | |||||
* BaseElasticsearchService | |||||
* | |||||
* @author fxbin | |||||
* @version 1.0v | |||||
* @since 2019/9/16 15:44 | |||||
*/ | |||||
public abstract class BaseElasticsearchService { | |||||
@Resource | |||||
private ElasticsearchProperties elasticsearchProperties; | |||||
/** | |||||
* create elasticsearch index | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index | |||||
*/ | |||||
public void createIndex(String index, Person person) { | |||||
try { | |||||
CreateIndexRequest request = new CreateIndexRequest(index); | |||||
// Settings for this index | |||||
request.settings(Settings.builder() | |||||
.put("index.number_of_shards", elasticsearchProperties.getIndex().getNumberOfShards()) | |||||
.put("index.number_of_replicas", elasticsearchProperties.getIndex().getNumberOfReplicas())); | |||||
XContentBuilder builder = XContentFactory.jsonBuilder(); | |||||
builder.startObject(); | |||||
{ | |||||
builder.startObject("properties"); | |||||
{ | |||||
builder.startObject("message"); | |||||
{ | |||||
Map<String, Object> map = | |||||
BeanUtils.toMap(person); | |||||
map.keySet().forEach(key -> { | |||||
try { | |||||
builder.field(key, "text"); | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
}); | |||||
} | |||||
builder.endObject(); | |||||
} | |||||
builder.endObject(); | |||||
} | |||||
builder.endObject(); | |||||
request.mapping(builder); | |||||
} catch (IOException e) { | |||||
throw new ElasticsearchException("创建Elasticsearch索引 {" + index + "} 失败"); | |||||
} | |||||
} | |||||
/** | |||||
* build IndexRequest | |||||
* | |||||
* @author fxbin | |||||
* @param index elasticsearch index name | |||||
* @return {@link org.elasticsearch.action.index.IndexRequest} | |||||
*/ | |||||
public IndexRequest buildIndexRequest(String index) { | |||||
return new IndexRequest(index); | |||||
} | |||||
} |
@@ -1,11 +0,0 @@ | |||||
package com.xlcoding.elasticsearch.service; | |||||
/** | |||||
* PersonService | |||||
* | |||||
* @author fxbin | |||||
* @version v1.0 | |||||
* @since 2019/9/15 23:07 | |||||
*/ | |||||
public interface PersonService { | |||||
} |
@@ -1,14 +0,0 @@ | |||||
package com.xlcoding.elasticsearch.service.impl; | |||||
import com.xlcoding.elasticsearch.service.BaseElasticsearchService; | |||||
import com.xlcoding.elasticsearch.service.PersonService; | |||||
/** | |||||
* PersonServiceImpl | |||||
* | |||||
* @author fxbin | |||||
* @version v1.0 | |||||
* @since 2019/9/15 23:08 | |||||
*/ | |||||
public class PersonServiceImpl extends BaseElasticsearchService implements PersonService { | |||||
} |
@@ -0,0 +1,3 @@ | |||||
# Auto Configure | |||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ | |||||
com.xkcoding.elasticsearch.autoconfigure.ElasticsearchAutoConfiguration |
@@ -3,3 +3,9 @@ demo: | |||||
elasticsearch: | elasticsearch: | ||||
cluster-name: elasticsearch | cluster-name: elasticsearch | ||||
cluster-nodes: 20.20.0.27:9201 | cluster-nodes: 20.20.0.27:9201 | ||||
index: | |||||
number-of-replicas: 0 | |||||
number-of-shards: 3 | |||||
account: | |||||
username: | |||||
password: |
@@ -1,17 +0,0 @@ | |||||
package com.xdcoding.elasticsearch; | |||||
import org.junit.Test; | |||||
import org.junit.runner.RunWith; | |||||
import org.springframework.boot.test.context.SpringBootTest; | |||||
import org.springframework.test.context.junit4.SpringRunner; | |||||
@RunWith(SpringRunner.class) | |||||
@SpringBootTest | |||||
public class ElasticsearchApplicationTests { | |||||
@Test | |||||
public void contextLoads() { | |||||
} | |||||
} |
@@ -0,0 +1,64 @@ | |||||
package com.xkcoding.elasticsearch; | |||||
import com.xkcoding.elasticsearch.contants.ElasticsearchConstant; | |||||
import com.xkcoding.elasticsearch.model.Person; | |||||
import com.xkcoding.elasticsearch.service.PersonService; | |||||
import org.junit.Test; | |||||
import org.junit.runner.RunWith; | |||||
import org.springframework.boot.test.context.SpringBootTest; | |||||
import org.springframework.test.context.junit4.SpringRunner; | |||||
import javax.annotation.Resource; | |||||
import java.util.ArrayList; | |||||
import java.util.Date; | |||||
import java.util.List; | |||||
@RunWith(SpringRunner.class) | |||||
@SpringBootTest | |||||
public class ElasticsearchApplicationTests { | |||||
@Resource | |||||
private PersonService personService; | |||||
@Test | |||||
public void deleteIndexTest() { | |||||
personService.deleteIndex(ElasticsearchConstant.INDEX_NAME); | |||||
} | |||||
@Test | |||||
public void createIndexTest() { | |||||
personService.createIndex(ElasticsearchConstant.INDEX_NAME); | |||||
} | |||||
@Test | |||||
public void insertTest() { | |||||
List<Person> list = new ArrayList<>(); | |||||
list.add(Person.builder().age(11).birthday(new Date()).country("CN").id(1L).name("哈哈").remark("test1").build()); | |||||
list.add(Person.builder().age(22).birthday(new Date()).country("US").id(2L).name("hiahia").remark("test2").build()); | |||||
list.add(Person.builder().age(33).birthday(new Date()).country("ID").id(3L).name("呵呵").remark("test3").build()); | |||||
personService.insert(ElasticsearchConstant.INDEX_NAME, list); | |||||
} | |||||
@Test | |||||
public void updateTest() { | |||||
Person person = Person.builder().age(33).birthday(new Date()).country("ID_update").id(3L).name("呵呵update").remark("test3_update").build(); | |||||
List<Person> list = new ArrayList<>(); | |||||
list.add(person); | |||||
personService.update(ElasticsearchConstant.INDEX_NAME, list); | |||||
} | |||||
@Test | |||||
public void deleteTest() { | |||||
personService.delete(ElasticsearchConstant.INDEX_NAME, Person.builder().id(1L).build()); | |||||
} | |||||
@Test | |||||
public void searchListTest() { | |||||
List<Person> personList = personService.searchList(ElasticsearchConstant.INDEX_NAME); | |||||
System.out.println(personList); | |||||
} | |||||
} |