你知道的越多,不知道的就越多,業餘的像一棵小草!
你來,咱們一塊兒精進!你不來,我和你的競爭對手一塊兒精進!
java
編輯:業餘草
rrd.me/gBaFy
推薦:https://www.xttblog.com/?p=5120
1、ElasticSearch 簡介
一、簡介
ElasticSearch 是一個基於 Lucene 的搜索服務器。它提供了一個分佈式多員工能力的全文搜索引擎,基於 RESTful web 接口。Elasticsearch 是用 Java 語言開發的,並做爲 Apache 許可條款下的開放源碼發佈,是一種流行的企業級搜索引擎。git
ElasticSearch 用於雲計算中,可以達到實時搜索,穩定,可靠,快速,安裝使用方便。github
二、特性
分佈式的文檔存儲引擎web
分佈式的搜索引擎和分析引擎spring
分佈式,支持PB級數據數據庫
三、使用場景
搜索領域:如百度、谷歌,全文檢索等。apache
門戶網站:訪問統計、文章點贊、留言評論等。json
廣告推廣:記錄員工行爲數據、消費趨勢、員工羣體進行定製推廣等。後端
信息採集:記錄應用的埋點數據、訪問日誌數據等,方便大數據進行分析。數組
2、ElasticSearch 基礎概念
一、ElaticSearch 和 DB 的關係
在 Elasticsearch 中,文檔歸屬於一種類型 type,而這些類型存在於索引 index 中,咱們能夠列一些簡單的不一樣點,來類比傳統關係型數據庫:
Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices -> Types -> Documents -> Fields
Elasticsearch 集羣能夠包含多個索引 indices,每個索引能夠包含多個類型 types,每個類型包含多個文檔 documents,而後每一個文檔包含多個字段 Fields。而在 DB 中能夠有多個數據庫 Databases,每一個庫中能夠有多張表 Tables,沒個表中又包含多行Rows,每行包含多列Columns。
二、索引
索引基本概念(indices):
索引是含義相同屬性的文檔集合,是 ElasticSearch 的一個邏輯存儲,能夠理解爲關係型數據庫中的數據庫,ElasticSearch 能夠把索引數據存放到一臺服務器上,也能夠 sharding 後存到多臺服務器上,每一個索引有一個或多個分片,每一個分片能夠有多個副本。
索引類型(index_type):
索引能夠定義一個或多個類型,文檔必須屬於一個類型。在 ElasticSearch 中,一個索引對象能夠存儲多個不一樣用途的對象,經過索引類型能夠區分單個索引中的不一樣對象,能夠理解爲關係型數據庫中的表。每一個索引類型能夠有不一樣的結構,可是不一樣的索引類型不能爲相同的屬性設置不一樣的類型。
三、文檔
文檔(document):
文檔是能夠被索引的基本數據單位。存儲在 ElasticSearch 中的主要實體叫文檔 document,能夠理解爲關係型數據庫中表的一行記錄。每一個文檔由多個字段構成,ElasticSearch 是一個非結構化的數據庫,每一個文檔能夠有不一樣的字段,而且有一個惟一的標識符。
四、映射
映射(mapping):
ElasticSearch 的 Mapping 很是相似於靜態語言中的數據類型:聲明一個變量爲 int 類型的變量,之後這個變量都只能存儲 int 類型的數據。一樣的,一個 number 類型的 mapping 字段只能存儲 number 類型的數據。
同語言的數據類型相比,Mapping 還有一些其餘的含義,Mapping 不只告訴 ElasticSearch 一個 Field 中是什麼類型的值, 它還告訴 ElasticSearch 如何索引數據以及數據是否能被搜索到。
ElaticSearch 默認是動態建立索引和索引類型的 Mapping 的。這就至關於無需定義 Solr 中的 Schema,無需指定各個字段的索引規則就能夠索引文件,很方便。但有時方便就表明着不靈活。好比,ElasticSearch 默認一個字段是要作分詞的,但咱們有時要搜索匹配整個字段卻不行。若有統計工做要記錄每一個城市出現的次數。對於 name 字段,若記錄 new york 文本,ElasticSearch 可能會把它拆分紅 new 和 york 這兩個詞,分別計算這個兩個單詞的次數,而不是咱們指望的 new york。
3、SpringBoot 項目引入 ElasticSearch 依賴
下面介紹下 SpringBoot 如何經過 elasticsearch-rest-high-level-client 工具操做 ElasticSearch,這裏須要說一下,爲何沒有使用 Spring 家族封裝的 spring-data-elasticsearch。
主要緣由是靈活性和更新速度,Spring 將 ElasticSearch 過分封裝,讓開發者很難跟 ES 的 DSL 查詢語句進行關聯。再者就是更新速度,ES 的更新速度是很是快,可是 spring-data-elasticsearch 更新速度比較緩慢。
因爲上面兩點,因此選擇了官方推出的 Java 客戶端 elasticsearch-rest-high-level-client,它的代碼寫法跟 DSL 語句很類似,懂 ES 查詢的使用其上手很快。
示例項目地址:https://github.com/my-dlq/blog-example/tree/master/springboot/springboot-elasticsearch-example
一、Maven 引入相關依賴
lombok:lombok 工具依賴。
fastjson:用於將 JSON 轉換對象的依賴。
spring-boot-starter-web: SpringBoot 的 Web 依賴。
elasticsearch:ElasticSearch:依賴,須要和 ES 版本保持一致。
elasticsearch-rest-high-level-client:用於操做 ES 的 Java 客戶端。
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>club.mydlq</groupId>
<artifactId>springboot-elasticsearch-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-elasticsearch-example</name>
<description>Demo project for Spring Boot ElasticSearch</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.61</version>
</dependency>
<!--elasticsearch-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.5.4</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.5.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
二、ElasticSearch 鏈接配置
(1)、application.yml 配置文件
爲了方便更改鏈接 ES 的鏈接配置,因此咱們將配置信息放置於 application.yaml 中:
#base
server:
port: 8080
#spring
spring:
application:
name: springboot-elasticsearch-example
#elasticsearch
elasticsearch:
schema: http
address: 127.0.0.1:9200
connectTimeout: 5000
socketTimeout: 5000
connectionRequestTimeout: 5000
maxConnectNum: 100
maxConnectPerRoute: 100
(2)、java 鏈接配置類
這裏須要寫一個 Java 配置類讀取 application 中的配置信息:
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
/**
* ElasticSearch 配置
*/
@Configuration
public class ElasticSearchConfig {
/** 協議 */
@Value("${elasticsearch.schema:http}")
private String schema;
/** 集羣地址,若是有多個用「,」隔開 */
@Value("${elasticsearch.address}")
private String address;
/** 鏈接超時時間 */
@Value("${elasticsearch.connectTimeout:5000}")
private int connectTimeout;
/** Socket 鏈接超時時間 */
@Value("${elasticsearch.socketTimeout:10000}")
private int socketTimeout;
/** 獲取鏈接的超時時間 */
@Value("${elasticsearch.connectionRequestTimeout:5000}")
private int connectionRequestTimeout;
/** 最大鏈接數 */
@Value("${elasticsearch.maxConnectNum:100}")
private int maxConnectNum;
/** 最大路由鏈接數 */
@Value("${elasticsearch.maxConnectPerRoute:100}")
private int maxConnectPerRoute;
@Bean
public RestHighLevelClient restHighLevelClient() {
// 拆分地址
List<HttpHost> hostLists = new ArrayList<>();
String[] hostList = address.split(",");
for (String addr : hostList) {
String host = addr.split(":")[0];
String port = addr.split(":")[1];
hostLists.add(new HttpHost(host, Integer.parseInt(port), schema));
}
// 轉換成 HttpHost 數組
HttpHost[] httpHost = hostLists.toArray(new HttpHost[]{});
// 構建鏈接對象
RestClientBuilder builder = RestClient.builder(httpHost);
// 異步鏈接延時配置
builder.setRequestConfigCallback(requestConfigBuilder -> {
requestConfigBuilder.setConnectTimeout(connectTimeout);
requestConfigBuilder.setSocketTimeout(socketTimeout);
requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeout);
return requestConfigBuilder;
});
// 異步鏈接數配置
builder.setHttpClientConfigCallback(httpClientBuilder -> {
httpClientBuilder.setMaxConnTotal(maxConnectNum);
httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);
return httpClientBuilder;
});
return new RestHighLevelClient(builder);
}
}
4、索引操做示例
這裏示例會指出經過 Kibana 的 Restful 工具操做與對應的 Java 代碼操做的兩個示例。擴展:某小公司RESTful、共用接口、先後端分離、接口約定的實踐
一、Restful 操做示例
建立索引
建立名爲 mydlq-user 的索引與對應 Mapping。
PUT /mydlq-user
{
"mappings": {
"doc": {
"dynamic": true,
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"address": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"remark": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"age": {
"type": "integer"
},
"salary": {
"type": "float"
},
"birthDate": {
"type": "date",
"format": "yyyy-MM-dd"
},
"createTime": {
"type": "date"
}
}
}
}
}
刪除索引
刪除 mydlq-user 索引。
DELETE /mydlq-user
二、Java 代碼示例
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Slf4j
@Service
public class IndexService2 {
@Autowired
private RestHighLevelClient restHighLevelClient;
/**
* 建立索引
*/
public void createIndex() {
try {
// 建立 Mapping
XContentBuilder mapping = XContentFactory.jsonBuilder()
.startObject()
.field("dynamic", true)
.startObject("properties")
.startObject("name")
.field("type","text")
.startObject("fields")
.startObject("keyword")
.field("type","keyword")
.endObject()
.endObject()
.endObject()
.startObject("address")
.field("type","text")
.startObject("fields")
.startObject("keyword")
.field("type","keyword")
.endObject()
.endObject()
.endObject()
.startObject("remark")
.field("type","text")
.startObject("fields")
.startObject("keyword")
.field("type","keyword")
.endObject()
.endObject()
.endObject()
.startObject("age")
.field("type","integer")
.endObject()
.startObject("salary")
.field("type","float")
.endObject()
.startObject("birthDate")
.field("type","date")
.field("format", "yyyy-MM-dd")
.endObject()
.startObject("createTime")
.field("type","date")
.endObject()
.endObject()
.endObject();
// 建立索引配置信息,配置
Settings settings = Settings.builder()
.put("index.number_of_shards", 1)
.put("index.number_of_replicas", 0)
.build();
// 新建建立索引請求對象,而後設置索引類型(ES 7.0 將不存在索引類型)和 mapping 與 index 配置
CreateIndexRequest request = new CreateIndexRequest("mydlq-user", settings);
request.mapping("doc", mapping);
// RestHighLevelClient 執行建立索引
CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
// 判斷是否建立成功
boolean isCreated = createIndexResponse.isAcknowledged();
log.info("是否建立成功:{}", isCreated);
} catch (IOException e) {
log.error("", e);
}
}
/**
* 刪除索引
*/
public void deleteIndex() {
try {
// 新建刪除索引請求對象
DeleteIndexRequest request = new DeleteIndexRequest("mydlq-user");
// 執行刪除索引
AcknowledgedResponse acknowledgedResponse = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
// 判斷是否刪除成功
boolean siDeleted = acknowledgedResponse.isAcknowledged();
log.info("是否刪除成功:{}", siDeleted);
} catch (IOException e) {
log.error("", e);
}
}
}
5、文檔操做示例
一、Restful 操做示例
增長文檔信息
在索引 mydlq-user 中增長一條文檔信息。
POST /mydlq-user/doc
{
"address": "北京市",
"age": 29,
"birthDate": "1990-01-10",
"createTime": 1579530727699,
"name": "張三",
"remark": "來自北京市的張先生",
"salary": 100
}
獲取文檔信息
獲取 mydlq-user 的索引 id=1 的文檔信息。
GET /mydlq-user/doc/1
更新文檔信息
更新以前建立的 id=1 的文檔信息。
PUT /mydlq-user/doc/1
{
"address": "北京市海淀區",
"age": 29,
"birthDate": "1990-01-10",
"createTime": 1579530727699,
"name": "張三",
"remark": "來自北京市的張先生",
"salary": 100
}
刪除文檔信息
刪除以前建立的 id=1 的文檔信息。
DELETE /mydlq-user/doc/1
二、Java 代碼示例
import club.mydlq.elasticsearch.model.entity.UserInfo;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
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.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.Date;
@Slf4j
@Service
public class IndexService {
@Autowired
private RestHighLevelClient restHighLevelClient;
/**
* 增長文檔信息
*/
public void addDocument() {
try {
// 建立索引請求對象
IndexRequest indexRequest = new IndexRequest("mydlq-user", "doc", "1");
// 建立員工信息
UserInfo userInfo = new UserInfo();
userInfo.setName("張三");
userInfo.setAge(29);
userInfo.setSalary(100.00f);
userInfo.setAddress("北京市");
userInfo.setRemark("來自北京市的張先生");
userInfo.setCreateTime(new Date());
userInfo.setBirthDate("1990-01-10");
// 將對象轉換爲 byte 數組
byte[] json = JSON.toJSONBytes(userInfo);
// 設置文檔內容
indexRequest.source(json, XContentType.JSON);
// 執行增長文檔
IndexResponse response = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
log.info("建立狀態:{}", response.status());
} catch (Exception e) {
log.error("", e);
}
}
/**
* 獲取文檔信息
*/
public void getDocument() {
try {
// 獲取請求對象
GetRequest getRequest = new GetRequest("mydlq-user", "doc", "1");
// 獲取文檔信息
GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
// 將 JSON 轉換成對象
if (getResponse.isExists()) {
UserInfo userInfo = JSON.parseObject(getResponse.getSourceAsBytes(), UserInfo.class);
log.info("員工信息:{}", userInfo);
}
} catch (IOException e) {
log.error("", e);
}
}
/**
* 更新文檔信息
*/
public void updateDocument() {
try {
// 建立索引請求對象
UpdateRequest updateRequest = new UpdateRequest("mydlq-user", "doc", "1");
// 設置員工更新信息
UserInfo userInfo = new UserInfo();
userInfo.setSalary(200.00f);
userInfo.setAddress("北京市海淀區");
// 將對象轉換爲 byte 數組
byte[] json = JSON.toJSONBytes(userInfo);
// 設置更新文檔內容
updateRequest.doc(json, XContentType.JSON);
// 執行更新文檔
UpdateResponse response = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
log.info("建立狀態:{}", response.status());
} catch (Exception e) {
log.error("", e);
}
}
/**
* 刪除文檔信息
*/
public void deleteDocument() {
try {
// 建立刪除請求對象
DeleteRequest deleteRequest = new DeleteRequest("mydlq-user", "doc", "1");
// 執行刪除文檔
DeleteResponse response = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
log.info("刪除狀態:{}", response.status());
} catch (IOException e) {
log.error("", e);
}
}
}
6、插入初始化數據
執行查詢示例前,先往索引中插入一批數據:
一、單條插入
POST mydlq-user/_doc
{"name":"零零","address":"北京市豐臺區","remark":"低層員工","age":29,"salary":3000,"birthDate":"1990-11-11","createTime":"2019-11-11T08:18:00.000Z"}
二、批量插入
POST _bulk
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"劉一","address":"北京市豐臺區","remark":"低層員工","age":30,"salary":3000,"birthDate":"1989-11-11","createTime":"2019-03-15T08:18:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"陳二","address":"北京市昌平區","remark":"中層員工","age":27,"salary":7900,"birthDate":"1992-01-25","createTime":"2019-11-08T11:15:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"張三","address":"北京市房山區","remark":"中層員工","age":28,"salary":8800,"birthDate":"1991-10-05","createTime":"2019-07-22T13:22:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"李四","address":"北京市大興區","remark":"高層員工","age":26,"salary":9000,"birthDate":"1993-08-18","createTime":"2019-10-17T15:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"王五","address":"北京市密雲區","remark":"低層員工","age":31,"salary":4800,"birthDate":"1988-07-20","createTime":"2019-05-29T09:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"趙六","address":"北京市通州區","remark":"中層員工","age":32,"salary":6500,"birthDate":"1987-06-02","createTime":"2019-12-10T18:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"孫七","address":"北京市朝陽區","remark":"中層員工","age":33,"salary":7000,"birthDate":"1986-04-15","createTime":"2019-06-06T13:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"周八","address":"北京市西城區","remark":"低層員工","age":32,"salary":5000,"birthDate":"1987-09-26","createTime":"2019-01-26T14:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"吳九","address":"北京市海淀區","remark":"高層員工","age":30,"salary":11000,"birthDate":"1989-11-25","createTime":"2019-09-07T13:34:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"鄭十","address":"北京市東城區","remark":"低層員工","age":29,"salary":5000,"birthDate":"1990-12-25","createTime":"2019-03-06T12:08:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"蕭十一","address":"北京市平谷區","remark":"低層員工","age":29,"salary":3300,"birthDate":"1990-11-11","createTime":"2019-03-10T08:17:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"曹十二","address":"北京市懷柔區","remark":"中層員工","age":27,"salary":6800,"birthDate":"1992-01-25","createTime":"2019-12-03T11:09:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"吳十三","address":"北京市延慶區","remark":"中層員工","age":25,"salary":7000,"birthDate":"1994-10-05","createTime":"2019-07-27T14:22:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"馮十四","address":"北京市密雲區","remark":"低層員工","age":25,"salary":3000,"birthDate":"1994-08-18","createTime":"2019-04-22T15:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"蔣十五","address":"北京市通州區","remark":"低層員工","age":31,"salary":2800,"birthDate":"1988-07-20","createTime":"2019-06-13T10:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"苗十六","address":"北京市門頭溝區","remark":"高層員工","age":32,"salary":11500,"birthDate":"1987-06-02","createTime":"2019-11-11T18:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"魯十七","address":"北京市石景山區","remark":"高員工","age":33,"salary":9500,"birthDate":"1986-04-15","createTime":"2019-06-06T14:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"沈十八","address":"北京市朝陽區","remark":"中層員工","age":31,"salary":8300,"birthDate":"1988-09-26","createTime":"2019-09-25T14:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"呂十九","address":"北京市西城區","remark":"低層員工","age":31,"salary":4500,"birthDate":"1988-11-25","createTime":"2019-09-22T13:34:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"丁二十","address":"北京市東城區","remark":"低層員工","age":33,"salary":2100,"birthDate":"1986-12-25","createTime":"2019-03-07T12:08:00.000Z"}
三、查詢數據
插入完成後再查詢數據,查看以前插入的數據是否存在:
GET mydlq-user/_search
執行後獲得下面記錄:
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 20,
"max_score": 1,
"hits": [
{
"_index": "mydlq-user",
"_type": "_doc",
"_id": "BeN0BW8B7BNodGwRFTRj",
"_score": 1,
"_source": {
"name": "劉一",
"address": "北京市豐臺區",
"remark": "低層員工",
"age": 30,
"salary": 3000,
"birthDate": "1989-11-11",
"createTime": "2019-03-15T08:18:00.000Z"
}
},
{
"_index": "mydlq-user",
"_type": "_doc",
"_id": "BuN0BW8B7BNodGwRFTRj",
"_score": 1,
"_source": {
"name": "陳二",
"address": "北京市昌平區",
"remark": "中層員工",
"age": 27,
"salary": 7900,
"birthDate": "1992-01-25",
"createTime": "2019-11-08T11:15:00.000Z"
}
},
{
"_index": "mydlq-user",
"_type": "_doc",
"_id": "B-N0BW8B7BNodGwRFTRj",
"_score": 1,
"_source": {
"name": "張三",
"address": "北京市房山區",
"remark": "中層員工",
"age": 28,
"salary": 8800,
"birthDate": "1991-10-05",
"createTime": "2019-07-22T13:22:00.000Z"
}
},
{
"_index": "mydlq-user",
"_type": "_doc",
"_id": "CON0BW8B7BNodGwRFTRj",
"_score": 1,
"_source": {
"name": "李四",
"address": "北京市大興區",
"remark": "高層員工",
"age": 26,
"salary": 9000,
"birthDate": "1993-08-18",
"createTime": "2019-10-17T15:00:00.000Z"
}
},
{
"_index": "mydlq-user",
"_type": "_doc",
"_id": "CeN0BW8B7BNodGwRFTRj",
"_score": 1,
"_source": {
"name": "王五",
"address": "北京市密雲區",
"remark": "低層員工",
"age": 31,
"salary": 4800,
"birthDate": "1988-07-20",
"createTime": "2019-05-29T09:00:00.000Z"
}
},
{
"_index": "mydlq-user",
"_type": "_doc",
"_id": "CuN0BW8B7BNodGwRFTRj",
"_score": 1,
"_source": {
"name": "趙六",
"address": "北京市通州區",
"remark": "中層員工",
"age": 32,
"salary": 6500,
"birthDate": "1987-06-02",
"createTime": "2019-12-10T18:00:00.000Z"
}
},
{
"_index": "mydlq-user",
"_type": "_doc",
"_id": "C-N0BW8B7BNodGwRFTRj",
"_score": 1,
"_source": {
"name": "孫七",
"address": "北京市朝陽區",
"remark": "中層員工",
"age": 33,
"salary": 7000,
"birthDate": "1986-04-15",
"createTime": "2019-06-06T13:00:00.000Z"
}
},
{
"_index": "mydlq-user",
"_type": "_doc",
"_id": "DON0BW8B7BNodGwRFTRj",
"_score": 1,
"_source": {
"name": "周八",
"address": "北京市西城區",
"remark": "低層員工",
"age": 32,
"salary": 5000,
"birthDate": "1987-09-26",
"createTime": "2019-01-26T14:00:00.000Z"
}
},
{
"_index": "mydlq-user",
"_type": "_doc",
"_id": "DeN0BW8B7BNodGwRFTRj",
"_score": 1,
"_source": {
"name": "吳九",
"address": "北京市海淀區",
"remark": "高層員工",
"age": 30,
"salary": 11000,
"birthDate": "1989-11-25",
"createTime": "2019-09-07T13:34:00.000Z"
}
},
{
"_index": "mydlq-user",
"_type": "_doc",
"_id": "DuN0BW8B7BNodGwRFTRj",
"_score": 1,
"_source": {
"name": "鄭十",
"address": "北京市東城區",
"remark": "低層員工",
"age": 29,
"salary": 5000,
"birthDate": "1990-12-25",
"createTime": "2019-03-06T12:08:00.000Z"
}
}
]
}
}
7、查詢操做示例
一、精確查詢(term)
(1)、Restful 操做示例
精確查詢
精確查詢,查詢地址爲 北京市通州區 的人員信息:
查詢條件不會進行分詞,可是查詢內容可能會分詞,致使查詢不到。以前在建立索引時設置 Mapping 中 address 字段存在 keyword 字段是專門用於不分詞查詢的子字段。
GET mydlq-user/_search
{
"query": {
"term": {
"address.keyword": {
"value": "北京市通州區"
}
}
}
}
精確查詢-多內容查詢
精確查詢,查詢地址爲 北京市豐臺區、北京市昌平區 或 北京市大興區 的人員信息:
GET mydlq-user/_search
{
"query": {
"terms": {
"address.keyword": [
"北京市豐臺區",
"北京市昌平區",
"北京市大興區"
]
}
}
}
(2)、Java 代碼示例
import club.mydlq.elasticsearch.model.entity.UserInfo;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
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.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Slf4j
@Service
public class TermQueryService {
@Autowired
private RestHighLevelClient restHighLevelClient;
/**
* 精確查詢(查詢條件不會進行分詞,可是查詢內容可能會分詞,致使查詢不到)
*/
public void termQuery() {
try {
// 構建查詢條件(注意:termQuery 支持多種格式查詢,如 boolean、int、double、string 等,這裏使用的是 string 的查詢)
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.termQuery("address.keyword", "北京市通州區"));
// 建立查詢請求對象,將查詢對象配置到其中
SearchRequest searchRequest = new SearchRequest("mydlq-user");
searchRequest.source(searchSourceBuilder);
// 執行查詢,而後處理響應結果
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 根據狀態和數據條數驗證是否返回了數據
if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
SearchHits hits = searchResponse.getHits();
for (SearchHit hit : hits) {
// 將 JSON 轉換成對象
UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
// 輸出查詢信息
log.info(userInfo.toString());
}
}
} catch (IOException e) {
log.error("", e);
}
}
/**
* 多個內容在一個字段中進行查詢
*/
public void termsQuery() {
try {
// 構建查詢條件(注意:termsQuery 支持多種格式查詢,如 boolean、int、double、string 等,這裏使用的是 string 的查詢)
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.termsQuery("address.keyword", "北京市豐臺區", "北京市昌平區", "北京市大興區"));
// 建立查詢請求對象,將查詢對象配置到其中
SearchRequest searchRequest = new SearchRequest("mydlq-user");
searchRequest.source(searchSourceBuilder);
// 執行查詢,而後處理響應結果
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 根據狀態和數據條數驗證是否返回了數據
if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
SearchHits hits = searchResponse.getHits();
for (SearchHit hit : hits) {
// 將 JSON 轉換成對象
UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
// 輸出查詢信息
log.info(userInfo.toString());
}
}
} catch (IOException e) {
log.error("", e);
}
}
}
二、匹配查詢(match)
(1)、Restful 操做示例
匹配查詢所有數據與分頁
匹配查詢符合條件的全部數據,而且設置以 salary 字段升序排序,並設置分頁:
GET mydlq-user/_search
{
"query": {
"match_all": {}
},
"from": 0,
"size": 10,
"sort": [
{
"salary": {
"order": "asc"
}
}
]
}
匹配查詢數據
匹配查詢地址爲 通州區 的數據:
GET mydlq-user/_search
{
"query": {
"match": {
"address": "通州區"
}
}
}
詞語匹配查詢
詞語匹配進行查詢,匹配 address 中爲 北京市通州區 的員工信息:
GET mydlq-user/_search
{
"query": {
"match_phrase": {
"address": "北京市通州區"
}
}
}
內容多字段查詢
查詢在字段 address、remark 中存在 北京 內容的員工信息:
GET mydlq-user/_search
{
"query": {
"multi_match": {
"query": "北京",
"fields": ["address","remark"]
}
}
}
(2)、Java 代碼示例
import club.mydlq.elasticsearch.model.entity.UserInfo;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
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.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Slf4j
@Service
public class MatchQueryService {
@Autowired
private RestHighLevelClient restHighLevelClient;
/**
* 匹配查詢符合條件的全部數據,並設置分頁
*/
public Object matchAllQuery() {
try {
// 構建查詢條件
MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
// 建立查詢源構造器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(matchAllQueryBuilder);
// 設置分頁
searchSourceBuilder.from(0);
searchSourceBuilder.size(3);
// 設置排序
searchSourceBuilder.sort("salary", SortOrder.ASC);
// 建立查詢請求對象,將查詢對象配置到其中
SearchRequest searchRequest = new SearchRequest("mydlq-user");
searchRequest.source(searchSourceBuilder);
// 執行查詢,而後處理響應結果
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 根據狀態和數據條數驗證是否返回了數據
if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
SearchHits hits = searchResponse.getHits();
for (SearchHit hit : hits) {
// 將 JSON 轉換成對象
UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
// 輸出查詢信息
log.info(userInfo.toString());
}
}
} catch (IOException e) {
log.error("", e);
}
}
/**
* 匹配查詢數據
*/
public Object matchQuery() {
try {
// 構建查詢條件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchQuery("address", "*通州區"));
// 建立查詢請求對象,將查詢對象配置到其中
SearchRequest searchRequest = new SearchRequest("mydlq-user");
searchRequest.source(searchSourceBuilder);
// 執行查詢,而後處理響應結果
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 根據狀態和數據條數驗證是否返回了數據
if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
SearchHits hits = searchResponse.getHits();
for (SearchHit hit : hits) {
// 將 JSON 轉換成對象
UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
// 輸出查詢信息
log.info(userInfo.toString());
}
}
} catch (IOException e) {
log.error("", e);
}
}
/**
* 詞語匹配查詢
*/
public Object matchPhraseQuery() {
try {
// 構建查詢條件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchPhraseQuery("address", "北京市通州區"));
// 建立查詢請求對象,將查詢對象配置到其中
SearchRequest searchRequest = new SearchRequest("mydlq-user");
searchRequest.source(searchSourceBuilder);
// 執行查詢,而後處理響應結果
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 根據狀態和數據條數驗證是否返回了數據
if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
SearchHits hits = searchResponse.getHits();
for (SearchHit hit : hits) {
// 將 JSON 轉換成對象
UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
// 輸出查詢信息
log.info(userInfo.toString());
}
}
} catch (IOException e) {
log.error("", e);
}
}
/**
* 內容在多字段中進行查詢
*/
public Object matchMultiQuery() {
try {
// 構建查詢條件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.multiMatchQuery("北京市", "address", "remark"));
// 建立查詢請求對象,將查詢對象配置到其中
SearchRequest searchRequest = new SearchRequest("mydlq-user");
searchRequest.source(searchSourceBuilder);
// 執行查詢,而後處理響應結果
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 根據狀態和數據條數驗證是否返回了數據
if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
SearchHits hits = searchResponse.getHits();
for (SearchHit hit : hits) {
// 將 JSON 轉換成對象
UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
// 輸出查詢信息
log.info(userInfo.toString());
}
}
} catch (IOException e) {
log.error("", e);
}
}
}
三、模糊查詢(fuzzy)
(1)、Restful 操做示例
模糊查詢全部以 三 結尾的姓名
GET mydlq-user/_search
{
"query": {
"fuzzy": {
"name": "三"
}
}
}
(2)、Java 代碼示例
import club.mydlq.elasticsearch.model.entity.UserInfo;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
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.common.unit.Fuzziness;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Slf4j
@Service
public class FuzzyQueryService {
@Autowired
private RestHighLevelClient restHighLevelClient;
/**
* 模糊查詢全部以 「三」 結尾的姓名
*/
public Object fuzzyQuery() {
try {
// 構建查詢條件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.fuzzyQuery("name", "三").fuzziness(Fuzziness.AUTO));
// 建立查詢請求對象,將查詢對象配置到其中
SearchRequest searchRequest = new SearchRequest("mydlq-user");
searchRequest.source(searchSourceBuilder);
// 執行查詢,而後處理響應結果
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 根據狀態和數據條數驗證是否返回了數據
if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
SearchHits hits = searchResponse.getHits();
for (SearchHit hit : hits) {
// 將 JSON 轉換成對象
UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
// 輸出查詢信息
log.info(userInfo.toString());
}
}
} catch (IOException e) {
log.error("", e);
}
}
}
四、範圍查詢(range)
(1)、Restful 操做示例
查詢歲數 ≥ 30 歲的員工數據:
GET /mydlq-user/_search
{
"query": {
"range": {
"age": {
"gte": 30
}
}
}
}
查詢生日距離如今 30 年間的員工數據:
GET mydlq-user/_search
{
"query": {
"range": {
"birthDate": {
"gte": "now-30y"
}
}
}
}
(2)、Java 代碼示例
import club.mydlq.elasticsearch.model.entity.UserInfo;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
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.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Slf4j
@Service
public class RangeQueryService {
@Autowired
private RestHighLevelClient restHighLevelClient;
/**
* 查詢歲數 ≥ 30 歲的員工數據
*/
public void rangeQuery() {
try {
// 構建查詢條件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.rangeQuery("age").gte(30));
// 建立查詢請求對象,將查詢對象配置到其中
SearchRequest searchRequest = new SearchRequest("mydlq-user");
searchRequest.source(searchSourceBuilder);
// 執行查詢,而後處理響應結果
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 根據狀態和數據條數驗證是否返回了數據
if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
SearchHits hits = searchResponse.getHits();
for (SearchHit hit : hits) {
// 將 JSON 轉換成對象
UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
// 輸出查詢信息
log.info(userInfo.toString());
}
}
} catch (IOException e) {
log.error("", e);
}
}
/**
* 查詢距離如今 30 年間的員工數據
* [年(y)、月(M)、星期(w)、天(d)、小時(h)、分鐘(m)、秒(s)]
* 例如:
* now-1h 查詢一小時內範圍
* now-1d 查詢一天內時間範圍
* now-1y 查詢最近一年內的時間範圍
*/
public void dateRangeQuery() {
try {
// 構建查詢條件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// includeLower(是否包含下邊界)、includeUpper(是否包含上邊界)
searchSourceBuilder.query(QueryBuilders.rangeQuery("birthDate")
.gte("now-30y").includeLower(true).includeUpper(true));
// 建立查詢請求對象,將查詢對象配置到其中
SearchRequest searchRequest = new SearchRequest("mydlq-user");
searchRequest.source(searchSourceBuilder);
// 執行查詢,而後處理響應結果
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 根據狀態和數據條數驗證是否返回了數據
if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
SearchHits hits = searchResponse.getHits();
for (SearchHit hit : hits) {
// 將 JSON 轉換成對象
UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
// 輸出查詢信息
log.info(userInfo.toString());
}
}
} catch (IOException e) {
log.error("", e);
}
}
}
五、通配符查詢(wildcard)
(1)、Restful 操做示例
查詢全部以 「三」 結尾的姓名:
GET mydlq-user/_search
{
"query": {
"wildcard": {
"name.keyword": {
"value": "*三"
}
}
}
}
(2)、Java 代碼示例
import club.mydlq.elasticsearch.model.entity.UserInfo;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
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.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Slf4j
@Service
public class WildcardQueryService {
@Autowired
private RestHighLevelClient restHighLevelClient;
/**
* 查詢全部以 「三」 結尾的姓名
*
* *:表示多個字符(0個或多個字符)
* ?:表示單個字符
*/
public Object wildcardQuery() {
try {
// 構建查詢條件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.wildcardQuery("name.keyword", "*三"));
// 建立查詢請求對象,將查詢對象配置到其中
SearchRequest searchRequest = new SearchRequest("mydlq-user");
searchRequest.source(searchSourceBuilder);
// 執行查詢,而後處理響應結果
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 根據狀態和數據條數驗證是否返回了數據
if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
SearchHits hits = searchResponse.getHits();
for (SearchHit hit : hits) {
// 將 JSON 轉換成對象
UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
// 輸出查詢信息
log.info(userInfo.toString());
}
}
} catch (IOException e) {
log.error("", e);
}
}
}
六、布爾查詢(bool)
(1)、Restful 操做示例
查詢出生在 1990-1995 年期間,且地址在 北京市昌平區、北京市大興區、北京市房山區 的員工信息:
GET /mydlq-user/_search
{
"query": {
"bool": {
"filter": {
"range": {
"birthDate": {
"format": "yyyy",
"gte": 1990,
"lte": 1995
}
}
},
"must": [
{
"terms": {
"address.keyword": [
"北京市昌平區",
"北京市大興區",
"北京市房山區"
]
}
}
]
}
}
}
(2)、Java 代碼示例
import club.mydlq.elasticsearch.model.entity.UserInfo;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
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.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Slf4j
@Service
public class BoolQueryService {
@Autowired
private RestHighLevelClient restHighLevelClient;
public Object boolQuery() {
try {
// 建立 Bool 查詢構建器
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
// 構建查詢條件
boolQueryBuilder.must(QueryBuilders.termsQuery("address.keyword", "北京市昌平區", "北京市大興區", "北京市房山區"))
.filter().add(QueryBuilders.rangeQuery("birthDate").format("yyyy").gte("1990").lte("1995"));
// 構建查詢源構建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(boolQueryBuilder);
// 建立查詢請求對象,將查詢對象配置到其中
SearchRequest searchRequest = new SearchRequest("mydlq-user");
searchRequest.source(searchSourceBuilder);
// 執行查詢,而後處理響應結果
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 根據狀態和數據條數驗證是否返回了數據
if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
SearchHits hits = searchResponse.getHits();
for (SearchHit hit : hits) {
// 將 JSON 轉換成對象
UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
// 輸出查詢信息
log.info(userInfo.toString());
}
}
}catch (IOException e){
log.error("",e);
}
}
}
8、聚合查詢操做示例
一、Metric 聚合分析
(1)、Restful 操做示例
統計員工總數、工資最高值、工資最低值、工資平均工資、工資總和:
GET /mydlq-user/_search
{
"size": 0,
"aggs": {
"salary_stats": {
"stats": {
"field": "salary"
}
}
}
}
統計員工工資最低值:
GET /mydlq-user/_search
{
"size": 0,
"aggs": {
"salary_min": {
"min": {
"field": "salary"
}
}
}
}
統計員工工資最高值:
GET /mydlq-user/_search
{
"size": 0,
"aggs": {
"salary_max": {
"max": {
"field": "salary"
}
}
}
}
統計員工工資平均值:
GET /mydlq-user/_search
{
"size": 0,
"aggs": {
"salary_avg": {
"avg": {
"field": "salary"
}
}
}
}
統計員工工資總值:
GET /mydlq-user/_search
{
"size": 0,
"aggs": {
"salary_sum": {
"sum": {
"field": "salary"
}
}
}
}
統計員工總數:
GET /mydlq-user/_search
{
"size": 0,
"aggs": {
"employee_count": {
"value_count": {
"field": "salary"
}
}
}
}
統計員工工資百分位:
GET /mydlq-user/_search
{
"size": 0,
"aggs": {
"salary_percentiles": {
"percentiles": {
"field": "salary"
}
}
}
}
(2)、Java 代碼示例
import lombok.extern.slf4j.Slf4j;
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.rest.RestStatus;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.metrics.avg.ParsedAvg;
import org.elasticsearch.search.aggregations.metrics.max.ParsedMax;
import org.elasticsearch.search.aggregations.metrics.min.ParsedMin;
import org.elasticsearch.search.aggregations.metrics.percentiles.ParsedPercentiles;
import org.elasticsearch.search.aggregations.metrics.percentiles.Percentile;
import org.elasticsearch.search.aggregations.metrics.stats.ParsedStats;
import org.elasticsearch.search.aggregations.metrics.sum.ParsedSum;
import org.elasticsearch.search.aggregations.metrics.sum.SumAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.valuecount.ParsedValueCount;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Slf4j
@Service
public class AggrMetricService {
@Autowired
private RestHighLevelClient restHighLevelClient;
/**
* stats 統計員工總數、員工工資最高值、員工工資最低值、員工平均工資、員工工資總和
*/
public Object aggregationStats() {
String responseResult = "";
try {
// 設置聚合條件
AggregationBuilder aggr = AggregationBuilders.stats("salary_stats").field("salary");
// 查詢源構建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.aggregation(aggr);
// 設置查詢結果不返回,只返回聚合結果
searchSourceBuilder.size(0);
// 建立查詢請求對象,將查詢條件配置到其中
SearchRequest request = new SearchRequest("mydlq-user");
request.source(searchSourceBuilder);
// 執行請求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 獲取響應中的聚合信息
Aggregations aggregations = response.getAggregations();
// 輸出內容
if (RestStatus.OK.equals(response.status()) || aggregations != null) {
// 轉換爲 Stats 對象
ParsedStats aggregation = aggregations.get("salary_stats");
log.info("-------------------------------------------");
log.info("聚合信息:");
log.info("count:{}", aggregation.getCount());
log.info("avg:{}", aggregation.getAvg());
log.info("max:{}", aggregation.getMax());
log.info("min:{}", aggregation.getMin());
log.info("sum:{}", aggregation.getSum());
log.info("-------------------------------------------");
}
// 根據具體業務邏輯返回不一樣結果,這裏爲了方便直接將返回響應對象Json串
responseResult = response.toString();
} catch (IOException e) {
log.error("", e);
}
return responseResult;
}
/**
* min 統計員工工資最低值
*/
public Object aggregationMin() {
String responseResult = "";
try {
// 設置聚合條件
AggregationBuilder aggr = AggregationBuilders.min("salary_min").field("salary");
// 查詢源構建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.aggregation(aggr);
searchSourceBuilder.size(0);
// 建立查詢請求對象,將查詢條件配置到其中
SearchRequest request = new SearchRequest("mydlq-user");
request.source(searchSourceBuilder);
// 執行請求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 獲取響應中的聚合信息
Aggregations aggregations = response.getAggregations();
// 輸出內容
if (RestStatus.OK.equals(response.status()) || aggregations != null) {
// 轉換爲 Min 對象
ParsedMin aggregation = aggregations.get("salary_min");
log.info("-------------------------------------------");
log.info("聚合信息:");
log.info("min:{}", aggregation.getValue());
log.info("-------------------------------------------");
}
// 根據具體業務邏輯返回不一樣結果,這裏爲了方便直接將返回響應對象Json串
responseResult = response.toString();
} catch (IOException e) {
log.error("", e);
}
return responseResult;
}
/**
* max 統計員工工資最高值
*/
public Object aggregationMax() {
String responseResult = "";
try {
// 設置聚合條件
AggregationBuilder aggr = AggregationBuilders.max("salary_max").field("salary");
// 查詢源構建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.aggregation(aggr);
searchSourceBuilder.size(0);
// 建立查詢請求對象,將查詢條件配置到其中
SearchRequest request = new SearchRequest("mydlq-user");
request.source(searchSourceBuilder);
// 執行請求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 獲取響應中的聚合信息
Aggregations aggregations = response.getAggregations();
// 輸出內容
if (RestStatus.OK.equals(response.status()) || aggregations != null) {
// 轉換爲 Max 對象
ParsedMax aggregation = aggregations.get("salary_max");
log.info("-------------------------------------------");
log.info("聚合信息:");
log.info("max:{}", aggregation.getValue());
log.info("-------------------------------------------");
}
// 根據具體業務邏輯返回不一樣結果,這裏爲了方便直接將返回響應對象Json串
responseResult = response.toString();
} catch (IOException e) {
log.error("", e);
}
return responseResult;
}
/**
* avg 統計員工工資平均值
*/
public Object aggregationAvg() {
String responseResult = "";
try {
// 設置聚合條件
AggregationBuilder aggr = AggregationBuilders.avg("salary_avg").field("salary");
// 查詢源構建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.aggregation(aggr);
searchSourceBuilder.size(0);
// 建立查詢請求對象,將查詢條件配置到其中
SearchRequest request = new SearchRequest("mydlq-user");
request.source(searchSourceBuilder);
// 執行請求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 獲取響應中的聚合信息
Aggregations aggregations = response.getAggregations();
// 輸出內容
if (RestStatus.OK.equals(response.status()) || aggregations != null) {
// 轉換爲 Avg 對象
ParsedAvg aggregation = aggregations.get("salary_avg");
log.info("-------------------------------------------");
log.info("聚合信息:");
log.info("avg:{}", aggregation.getValue());
log.info("-------------------------------------------");
}
// 根據具體業務邏輯返回不一樣結果,這裏爲了方便直接將返回響應對象Json串
responseResult = response.toString();
} catch (IOException e) {
log.error("", e);
}
return responseResult;
}
/**
* sum 統計員工工資總值
*/
public Object aggregationSum() {
String responseResult = "";
try {
// 設置聚合條件
SumAggregationBuilder aggr = AggregationBuilders.sum("salary_sum").field("salary");
// 查詢源構建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.aggregation(aggr);
searchSourceBuilder.size(0);
// 建立查詢請求對象,將查詢條件配置到其中
SearchRequest request = new SearchRequest("mydlq-user");
request.source(searchSourceBuilder);
// 執行請求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 獲取響應中的聚合信息
Aggregations aggregations = response.getAggregations();
// 輸出內容
if (RestStatus.OK.equals(response.status()) || aggregations != null) {
// 轉換爲 Sum 對象
ParsedSum aggregation = aggregations.get("salary_sum");
log.info("-------------------------------------------");
log.info("聚合信息:");
log.info("sum:{}", String.valueOf((aggregation.getValue())));
log.info("-------------------------------------------");
}
// 根據具體業務邏輯返回不一樣結果,這裏爲了方便直接將返回響應對象Json串
responseResult = response.toString();
} catch (IOException e) {
log.error("", e);
}
return responseResult;
}
/**
* count 統計員工總數
*/
public Object aggregationCount() {
String responseResult = "";
try {
// 設置聚合條件
AggregationBuilder aggr = AggregationBuilders.count("employee_count").field("salary");
// 查詢源構建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.aggregation(aggr);
searchSourceBuilder.size(0);
// 建立查詢請求對象,將查詢條件配置到其中
SearchRequest request = new SearchRequest("mydlq-user");
request.source(searchSourceBuilder);
// 執行請求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 獲取響應中的聚合信息
Aggregations aggregations = response.getAggregations();
// 輸出內容
if (RestStatus.OK.equals(response.status()) || aggregations != null) {
// 轉換爲 ValueCount 對象
ParsedValueCount aggregation = aggregations.get("employee_count");
log.info("-------------------------------------------");
log.info("聚合信息:");
log.info("count:{}", aggregation.getValue());
log.info("-------------------------------------------");
}
// 根據具體業務邏輯返回不一樣結果,這裏爲了方便直接將返回響應對象Json串
responseResult = response.toString();
} catch (IOException e) {
log.error("", e);
}
return responseResult;
}
/**
* percentiles 統計員工工資百分位
*/
public Object aggregationPercentiles() {
String responseResult = "";
try {
// 設置聚合條件
AggregationBuilder aggr = AggregationBuilders.percentiles("salary_percentiles").field("salary");
// 查詢源構建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.aggregation(aggr);
searchSourceBuilder.size(0);
// 建立查詢請求對象,將查詢條件配置到其中
SearchRequest request = new SearchRequest("mydlq-user");
request.source(searchSourceBuilder);
// 執行請求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 獲取響應中的聚合信息
Aggregations aggregations = response.getAggregations();
// 輸出內容
if (RestStatus.OK.equals(response.status()) || aggregations != null) {
// 轉換爲 Percentiles 對象
ParsedPercentiles aggregation = aggregations.get("salary_percentiles");
log.info("-------------------------------------------");
log.info("聚合信息:");
for (Percentile percentile : aggregation) {
log.info("百分位:{}:{}", percentile.getPercent(), percentile.getValue());
}
log.info("-------------------------------------------");
}
// 根據具體業務邏輯返回不一樣結果,這裏爲了方便直接將返回響應對象Json串
responseResult = response.toString();
} catch (IOException e) {
log.error("", e);
}
return responseResult;
}
}
二、Bucket 聚合分析
(1)、Restful 操做示例
按歲數進行聚合分桶,統計各個歲數員工的人數:
GET mydlq-user/_search
{
"size": 0,
"aggs": {
"age_bucket": {
"terms": {
"field": "age",
"size": "10"
}
}
}
}
按工資範圍進行聚合分桶,統計工資在 3000-5000、5000-9000 和 9000 以上的員工信息:
GET mydlq-user/_search
{
"aggs": {
"salary_range_bucket": {
"range": {
"field": "salary",
"ranges": [
{
"key": "低級員工",
"to": 3000
},{
"key": "中級員工",
"from": 5000,
"to": 9000
},{
"key": "高級員工",
"from": 9000
}
]
}
}
}
}
按照時間範圍進行分桶,統計 1985-1990 年和 1990-1995 年出生的員工信息:
GET mydlq-user/_search
{
"size": 10,
"aggs": {
"date_range_bucket": {
"date_range": {
"field": "birthDate",
"format": "yyyy",
"ranges": [
{
"key": "出生日期1985-1990的員工",
"from": "1985",
"to": "1990"
},{
"key": "出生日期1990-1995的員工",
"from": "1990",
"to": "1995"
}
]
}
}
}
}
按工資多少進行聚合分桶,設置統計的最小值爲 0,最大值爲 12000,區段間隔爲 3000:
GET mydlq-user/_search
{
"size": 0,
"aggs": {
"salary_histogram": {
"histogram": {
"field": "salary",
"extended_bounds": {
"min": 0,
"max": 12000
},
"interval": 3000
}
}
}
}
按出生日期進行分桶:
GET mydlq-user/_search
{
"size": 0,
"aggs": {
"birthday_histogram": {
"date_histogram": {
"format": "yyyy",
"field": "birthDate",
"interval": "year"
}
}
}
}
(2)、Java 代碼示例
import lombok.extern.slf4j.Slf4j;
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.rest.RestStatus;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.bucket.range.Range;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.List;
@Slf4j
@Service
public class AggrBucketService {
@Autowired
private RestHighLevelClient restHighLevelClient;
/**
* 按歲數進行聚合分桶
*/
public Object aggrBucketTerms() {
try {
AggregationBuilder aggr = AggregationBuilders.terms("age_bucket").field("age");
// 查詢源構建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.size(10);
searchSourceBuilder.aggregation(aggr);
// 建立查詢請求對象,將查詢條件配置到其中
SearchRequest request = new SearchRequest("mydlq-user");
request.source(searchSourceBuilder);
// 執行請求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 獲取響應中的聚合信息
Aggregations aggregations = response.getAggregations();
// 輸出內容
if (RestStatus.OK.equals(response.status())) {
// 分桶
Terms byCompanyAggregation = aggregations.get("age_bucket");
List<? extends Terms.Bucket> buckets = byCompanyAggregation.getBuckets();
// 輸出各個桶的內容
log.info("-------------------------------------------");
log.info("聚合信息:");
for (Terms.Bucket bucket : buckets) {
log.info("桶名:{} | 總數:{}", bucket.getKeyAsString(), bucket.getDocCount());
}
log.info("-------------------------------------------");
}
} catch (IOException e) {
log.error("", e);
}
}
/**
* 按工資範圍進行聚合分桶
*/
public Object aggrBucketRange() {
try {
AggregationBuilder aggr = AggregationBuilders.range("salary_range_bucket")
.field("salary")
.addUnboundedTo("低級員工", 3000)
.addRange("中級員工", 5000, 9000)
.addUnboundedFrom("高級員工", 9000);
// 查詢源構建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.size(0);
searchSourceBuilder.aggregation(aggr);
// 建立查詢請求對象,將查詢條件配置到其中
SearchRequest request = new SearchRequest("mydlq-user");
request.source(searchSourceBuilder);
// 執行請求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 獲取響應中的聚合信息
Aggregations aggregations = response.getAggregations();
// 輸出內容
if (RestStatus.OK.equals(response.status())) {
// 分桶
Range byCompanyAggregation = aggregations.get("salary_range_bucket");
List<? extends Range.Bucket> buckets = byCompanyAggregation.getBuckets();
// 輸出各個桶的內容
log.info("-------------------------------------------");
log.info("聚合信息:");
for (Range.Bucket bucket : buckets) {
log.info("桶名:{} | 總數:{}", bucket.getKeyAsString(), bucket.getDocCount());
}
log.info("-------------------------------------------");
}
} catch (IOException e) {
log.error("", e);
}
}
/**
* 按照時間範圍進行分桶
*/
public Object aggrBucketDateRange() {
try {
AggregationBuilder aggr = AggregationBuilders.dateRange("date_range_bucket")
.field("birthDate")
.format("yyyy")
.addRange("1985-1990", "1985", "1990")
.addRange("1990-1995", "1990", "1995");
// 查詢源構建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.size(0);
searchSourceBuilder.aggregation(aggr);
// 建立查詢請求對象,將查詢條件配置到其中
SearchRequest request = new SearchRequest("mydlq-user");
request.source(searchSourceBuilder);
// 執行請求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 獲取響應中的聚合信息
Aggregations aggregations = response.getAggregations();
// 輸出內容
if (RestStatus.OK.equals(response.status())) {
// 分桶
Range byCompanyAggregation = aggregations.get("date_range_bucket");
List<? extends Range.Bucket> buckets = byCompanyAggregation.getBuckets();
// 輸出各個桶的內容
log.info("-------------------------------------------");
log.info("聚合信息:");
for (Range.Bucket bucket : buckets) {
log.info("桶名:{} | 總數:{}", bucket.getKeyAsString(), bucket.getDocCount());
}
log.info("-------------------------------------------");
}
} catch (IOException e) {
log.error("", e);
}
}
/**
* 按工資多少進行聚合分桶
*/
public Object aggrBucketHistogram() {
try {
AggregationBuilder aggr = AggregationBuilders.histogram("salary_histogram")
.field("salary")
.extendedBounds(0, 12000)
.interval(3000);
// 查詢源構建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.size(0);
searchSourceBuilder.aggregation(aggr);
// 建立查詢請求對象,將查詢條件配置到其中
SearchRequest request = new SearchRequest("mydlq-user");
request.source(searchSourceBuilder);
// 執行請求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 獲取響應中的聚合信息
Aggregations aggregations = response.getAggregations();
// 輸出內容
if (RestStatus.OK.equals(response.status())) {
// 分桶
Histogram byCompanyAggregation = aggregations.get("salary_histogram");
List<? extends Histogram.Bucket> buckets = byCompanyAggregation.getBuckets();
// 輸出各個桶的內容
log.info("-------------------------------------------");
log.info("聚合信息:");
for (Histogram.Bucket bucket : buckets) {
log.info("桶名:{} | 總數:{}", bucket.getKeyAsString(), bucket.getDocCount());
}
log.info("-------------------------------------------");
}
} catch (IOException e) {
log.error("", e);
}
}
/**
* 按出生日期進行分桶
*/
public Object aggrBucketDateHistogram() {
try {
AggregationBuilder aggr = AggregationBuilders.dateHistogram("birthday_histogram")
.field("birthDate")
.interval(1)
.dateHistogramInterval(DateHistogramInterval.YEAR)
.format("yyyy");
// 查詢源構建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.size(0);
searchSourceBuilder.aggregation(aggr);
// 建立查詢請求對象,將查詢條件配置到其中
SearchRequest request = new SearchRequest("mydlq-user");
request.source(searchSourceBuilder);
// 執行請求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 獲取響應中的聚合信息
Aggregations aggregations = response.getAggregations();
// 輸出內容
if (RestStatus.OK.equals(response.status())) {
// 分桶
Histogram byCompanyAggregation = aggregations.get("birthday_histogram");
List<? extends Histogram.Bucket> buckets = byCompanyAggregation.getBuckets();
// 輸出各個桶的內容
log.info("-------------------------------------------");
log.info("聚合信息:");
for (Histogram.Bucket bucket : buckets) {
log.info("桶名:{} | 總數:{}", bucket.getKeyAsString(), bucket.getDocCount());
}
log.info("-------------------------------------------");
}
} catch (IOException e) {
log.error("", e);
}
}
}
三、Metric 與 Bucket 聚合分析
(1)、Restful 操做示例
按照員工歲數分桶、而後統計每一個歲數員工工資最高值:
GET mydlq-user/_search
{
"size": 0,
"aggs": {
"salary_bucket": {
"terms": {
"field": "age",
"size": "10"
},
"aggs": {
"salary_max_user": {
"top_hits": {
"size": 1,
"sort": [
{
"salary": {
"order": "desc"
}
}
]
}
}
}
}
}
}
(2)、Java 代碼示例
import lombok.extern.slf4j.Slf4j;
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.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.tophits.ParsedTopHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.List;
@Slf4j
@Service
public class AggrBucketMetricService {
@Autowired
private RestHighLevelClient restHighLevelClient;
/**
* topHits 按歲數分桶、而後統計每一個員工工資最高值
*/
public Object aggregationTopHits() {
try {
AggregationBuilder testTop = AggregationBuilders.topHits("salary_max_user")
.size(1)
.sort("salary", SortOrder.DESC);
AggregationBuilder salaryBucket = AggregationBuilders.terms("salary_bucket")
.field("age")
.size(10);
salaryBucket.subAggregation(testTop);
// 查詢源構建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.size(0);
searchSourceBuilder.aggregation(salaryBucket);
// 建立查詢請求對象,將查詢條件配置到其中
SearchRequest request = new SearchRequest("mydlq-user");
request.source(searchSourceBuilder);
// 執行請求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 獲取響應中的聚合信息
Aggregations aggregations = response.getAggregations();
// 輸出內容
if (RestStatus.OK.equals(response.status())) {
// 分桶
Terms byCompanyAggregation = aggregations.get("salary_bucket");
List<? extends Terms.Bucket> buckets = byCompanyAggregation.getBuckets();
// 輸出各個桶的內容
log.info("-------------------------------------------");
log.info("聚合信息:");
for (Terms.Bucket bucket : buckets) {
log.info("桶名:{}", bucket.getKeyAsString());
ParsedTopHits topHits = bucket.getAggregations().get("salary_max_user");
for (SearchHit hit:topHits.getHits()){
log.info(hit.getSourceAsString());
}
}
log.info("-------------------------------------------");
}
} catch (IOException e) {
log.error("", e);
}
}
}
本文分享自微信公衆號 - 業餘草(yyucao)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。