目录
一、高级客户端 (JAVA API 操作ES ) ★
官方文档:Getting started | Java REST Client [7.8] | Elastic
1、准备工作
1. 新建elasticsearch_demo Maven工程
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.6.RELEASE</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--elasticsearch的高级别rest客户端-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.8.0</version>
</dependency>
<!--elasticsearch的rest客户端-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>7.8.0</version>
</dependency>
<!--elasticsearch的核心jar包-->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.8.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--json转换的jar包-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
elasticsearch.host=localhost
elasticsearch.port=9200
3. 创建主目录,启动类
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
4. 创建配置类
@Configuration
@ConfigurationProperties(prefix = "elasticsearch")
public class ElasticSearchConfig {
private String host;
private Integer port;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
@Bean
public RestHighLevelClient restHighLevelClient(){
RestHighLevelClient restHighLevelClient =
new RestHighLevelClient(RestClient.builder(new HttpHost(host,port,"http")));
return restHighLevelClient;
}
}
5. 创建测试实体
1. 准备实体
@Data
public class Student implements Serializable {
private String name;
private Integer age;
private String remark;
}
6. 创建测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class ElasticSearchTest {
@Autowired
RestHighLevelClient client;
@Test
public void testResthightLevelClient() throws Exception {
System.out.println("restHighLevelClient = " + client);
}
}
2、索引操作
//创建索引
@Test
public void createIndex(){
//指定索引名,注意导包:高级客户端
CreateIndexRequest createIndexRequest = new CreateIndexRequest("person");
try {
//设置
createIndexRequest.mapping("{\n" +
" \"properties\": {\n" +
" \"name\": {\n" +
" \"type\": \"keyword\",\n" +
" \"index\": true,\n" +
" \"store\": true\n" +
" },\n" +
" \"age\": {\n" +
" \"type\": \"integer\",\n" +
" \"index\": true,\n" +
" \"store\": true\n" +
" },\n" +
" \"remark\": {\n" +
" \"type\": \"text\",\n" +
" \"index\": true,\n" +
" \"store\": true,\n" +
" \"analyzer\": \"ik_max_word\",\n" +
" \"search_analyzer\": \"ik_smart\"\n" +
" }\n" +
" }\n" +
" }", XContentType.JSON);
CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
System.out.println(createIndexResponse.isAcknowledged());
} catch (IOException e) {
e.printStackTrace();
}
}
//查看索引
@Test
public void getIndex(){
GetIndexRequest request = new GetIndexRequest("person");
try {
GetIndexResponse getIndexResponse = restHighLevelClient.indices().get(request, RequestOptions.DEFAULT);
System.out.println(getIndexResponse.getMappings());
System.out.println(getIndexResponse.getSettings());
} catch (IOException e) {
e.printStackTrace();
}
}
//删除索引
@Test
public void deleteIndex(){
DeleteIndexRequest request = new DeleteIndexRequest("person");
AcknowledgedResponse acknowledgedResponse = null;
try {
acknowledgedResponse = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(acknowledgedResponse.isAcknowledged());
}
3、文档操作
@RunWith(SpringRunner.class)
@SpringBootTest
public class ElasticSearchDocTest {
@Autowired
RestHighLevelClient restHighLevelClient;
@Test
public void testResthightLevelClient() throws Exception {
System.out.println("restHighLevelClient = " + restHighLevelClient);
}
//1.创建文档
@Test
public void createDoc(){
//创建请求对象,索引不存在,会自动创建
IndexRequest request = new IndexRequest("student");
request.id("1");
Student student = new Student();
student.setAge(18);
student.setName("robin");
student.setRemark("good man");
request.source(JSONObject.toJSONString(student), XContentType.JSON);
IndexResponse indexResponse = null;
try {
indexResponse = restHighLevelClient.index(request, RequestOptions.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(indexResponse.getResult());//CREATED
}
//2.修改文档
@Test
public void updateDoc(){
UpdateRequest request = new UpdateRequest("student", "1");
Student student = new Student();
student.setRemark("very good man");
//doc,指定字段修改
request.doc(JSONObject.toJSONString(student), XContentType.JSON);
try {
UpdateResponse updateResponse = restHighLevelClient.update(request, RequestOptions.DEFAULT);
System.out.println(updateResponse.getResult());//UPDATED
} catch (IOException e) {
e.printStackTrace();
}
}
//3.修改文档
@Test
public void getDoc(){
GetRequest request = new GetRequest("student", "1");
try {
GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);
System.out.println(response.getSourceAsString());//{"age":18,"name":"robin","remark":"very good man"}
} catch (IOException e) {
e.printStackTrace();
}
}
//4.批量操作
@Test
public void bulkDocument(){
BulkRequest bulkRequest = new BulkRequest();
Student student = new Student();
for(int i=0;i<10;i++){
student.setAge(18 + i);
student.setName("robin" + i);
student.setRemark("good man " + i);
bulkRequest.add(new IndexRequest("student")
.id(String.valueOf(10 + i))
.source(JSONObject.toJSONString(student), XContentType.JSON));
}
try {
BulkResponse response = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
for(BulkItemResponse itemResponse : response.getItems()){
System.out.println(itemResponse.isFailed());
}
} catch (IOException e) {
e.printStackTrace();
}
}
//5.删除文档
@Test
public void deleteDoc(){
DeleteRequest request = new DeleteRequest("student", "1");
try {
DeleteResponse delete = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
System.out.println(delete.getResult());//DELETED
} catch (IOException e) {
e.printStackTrace();
}
}
}
4、DSL操作
@RunWith(SpringRunner.class)
@SpringBootTest
public class ElasticSearchDSLTest {
private static final String MY_INDEX = "my_index";
@Autowired
RestHighLevelClient restHighLevelClient;
@Test
public void testResthightLevelClient() throws Exception {
System.out.println("restHighLevelClient = " + restHighLevelClient);
}
/**
* dsl查询文档:
* POST /my_index/_search
* {
* "query": {
* "match": {
* "title": "华为智能手机"
* }
* }
* }
* */
@Test
public void search(){
//创建请求
SearchRequest searchRequest = new SearchRequest(MY_INDEX);
//通过构造器封装构造条件
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(QueryBuilders.matchQuery("title","华为智能手机"));
searchRequest.source(builder);
try {
//高级客户端发送请求,设置默认参数
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
for(SearchHit hit : searchResponse.getHits().getHits()){
System.out.println(hit.getSourceAsString());
}
} catch (IOException e) {
e.printStackTrace();
}
}
//高亮查询
@Test
public void highlightSearch(){
SearchRequest request = new SearchRequest(MY_INDEX);
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(QueryBuilders.matchQuery("title","华为智能手机"));
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.preTags("<b style='color:red'>");
highlightBuilder.postTags("</b>");
builder.highlighter(highlightBuilder);
request.source(builder);
try {
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
for(SearchHit hit : response.getHits().getHits()){
System.out.println(hit.getSourceAsMap().get("title") + ":" +hit.getHighlightFields().get("title").fragments()[0].string());
//华为手机:<b style='color:red'>华为</b>手机
//华为笔记本电脑:<b style='color:red'>华为</b>笔记本电脑
}
} catch (IOException e) {
e.printStackTrace();
}
}
//聚合查询
@Test
public void aggsSearch() {
SearchRequest request = new SearchRequest(MY_INDEX);
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(QueryBuilders.matchAllQuery());
AggregationBuilder aggregationBuilder = AggregationBuilders
.terms("groupby_category").field("category");//桶聚合
aggregationBuilder.subAggregation(AggregationBuilders.avg("avg_price").field("price"));
builder.aggregation(aggregationBuilder);
request.source(builder);
try {
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
Aggregations aggregations = response.getAggregations();
Terms terms = aggregations.get("groupby_category");
terms.getBuckets().forEach(bucket -> {
Avg avg = bucket.getAggregations().get("avg_price");
System.out.println(bucket.getKeyAsString() + ":" + bucket.getDocCount() + "," + avg.getValue());
//华为:2,5444.0
//vivo:1,3600.0
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
二、SpringData Elasticsearch
Spring Data 是一个用于简化数据库、非关系型数据库、索引库访问,并支持云服务的开源框架。其主要目标是使得对数据的访问变得方便快捷。
官网:Spring Data
Spring Data Elasticsearch 基于 spring data API 简化 Elasticsearch操作,将原始操作Elasticsearch的客户端API 进行封装 。
1. 搭建工程
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.6.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
2. application.properties
# es服务地址
elasticsearch.host=127.0.0.1
# es服务端口
elasticsearch.port=9200
# 配置日志级别,开启debug日志
logging.level.com.atguigu=debug
3. 启动类
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
4. config
@ConfigurationProperties(prefix = "elasticsearch")
@Configuration
@Data
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
private String host ;
private Integer port ;
//重写父类方法
@Override
public RestHighLevelClient elasticsearchClient() {
RestClientBuilder builder = RestClient.builder(new HttpHost(host, port));
RestHighLevelClient restHighLevelClient = new RestHighLevelClient(builder);
return restHighLevelClient;
}
//get/set…
}
5. 添加实体类 bean 映射对象
@Data
@Document(indexName = "product",shards = 1, replicas = 1)
public class Product implements Serializable {
@Id
private Long id;
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String productName;
@Field(type = FieldType.Integer)
private Integer store;
@Field(type = FieldType.Double, index = true, store = false)
private double price;
}
6. dao 数据访问层,继承ElasticsearchRepos,指定映射、主键类型
@Repository
public interface ProductDao extends ElasticsearchRepository<Product,Long> {
}
1、测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class ElasticsearchTest {
@Autowired
private ElasticsearchRestTemplate elasticsearchTemplate;
@Autowired
private ProductDao productDao;
//添加文档
@Test
public void saveTest(){
//框架会隐式执行索引库创建和映射,无需执行下列代码。
// 创建索引,会根据Product类中的@Document注解信息来创建
// 配置映射,会根据Product类中的id、Field等字段来自动完成映射
Product product = new Product();
product.setId(1L);
product.setProductName("华为手机");
product.setStore(100);
product.setPrice(5000.00);
productDao.save(product);
System.out.println("添加成功...");
}
@Test
public void findById(){
//根据id查询文档
Product product = productDao.findById(1L).get();
System.out.println(product);
}
@Test
public void testFind(){
//查询全部,按照价格降序排序
Iterable<Product> products = productDao.findAll(Sort.by(Sort.Direction.DESC,"price"));
System.out.println("products = " + products);
}
}
2、自定义方法 ★
Spring Data 的另一个强大功能,是根据方法名称自动实现功能。
按照价格区间查询,定义这样的一个接口方法:
List<Product> findByPriceBetween(double price1, double price2);
@Test
public void queryByPriceBetween(){
List<Product> list = this.productDao.findByPriceBetween(2000.00, 5500.00);
for (Product product : list) {
System.out.println("product = " + product);
}
}
Keyword | Sample | Elasticsearch Query String |
---|---|---|
And | findByNameAndPrice | {"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}} |
Or | findByNameOrPrice | {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}} |
Is | findByName | {"bool" : {"must" : {"field" : {"name" : "?"}}}} |
Not | findByNameNot | {"bool" : {"must_not" : {"field" : {"name" : "?"}}}} |
Between | findByPriceBetween | {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
LessThanEqual | findByPriceLessThan | {"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
GreaterThanEqual | findByPriceGreaterThan | {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}} |
Before | findByPriceBefore | {"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
After | findByPriceAfter | {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}} |
Like | findByNameLike | {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}} |
StartingWith | findByNameStartingWith | {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}} |
EndingWith | findByNameEndingWith | {"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}} |
Contains/Containing | findByNameContaining | {"bool" : {"must" : {"field" : {"name" : {"query" : "?","analyze_wildcard" : true}}}}} |
In | findByNameIn(Collection<String>names) | {"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}} |
NotIn | findByNameNotIn(Collection<String>names) | {"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}} |
Near | findByStoreNear | Not Supported Yet ! |
True | findByAvailableTrue | {"bool" : {"must" : {"field" : {"available" : true}}}} |
False | findByAvailableFalse | {"bool" : {"must" : {"field" : {"available" : false}}}} |
OrderBy | findByAvailableTrueOrderByNameDesc | {"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"available" : true}}}} |