ES入門和簡單使用
項目背景:
項目中有一部分涉及到IM,所有的消息都是以一個JSON串的方式存儲到一張表中。表的結構大概如下
id | session_id | Message |
---|---|---|
1 | 1 | [json] |
產品提了個需求,可以通過消息關鍵字來搜索會話。但是目前的表是Json格式的,所以直接用sql語句搜索是不友好的。鑑於此,引入ElasticSearch (ES)。
官方地址
https://www.elastic.co/guide/en/elasticsearch/reference/6.0/getting-started.html
目前已經更新到7.8版本,我們項目裏面使用的是7.6
官網有具體的安裝、配置和使用教程,想深入學習的可以仔細閱讀官方文檔
簡單介紹
Elasticsearch是面向文檔(document oriented)的,這意味着它可以存儲整個對象或文檔(document)。然而它不僅僅是存儲,還會**索引(index)**每個文檔的內容使之可以被搜索。在Elasticsearch中,你可以對文檔(而非成行成列的數據)進行索引、搜索、排序、過濾。這種理解數據的方式與以往完全不同,這也是Elasticsearch能夠執行復雜的全文搜索的原因之一。
同傳統數據庫的對比
Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices -> Types -> Documents -> Fields
Elasticsearch集羣可以包含多個索引(indices)(數據庫),每一個索引可以包含多個類型(types)(表),每一個類型包含多個文檔(documents)(行),然後每個文檔包含多個字段(Fields)(列)。
簡單使用
1. query
單條件單字段匹配
"query": {
"match": {
"event": { //字段名稱
"query": "BitSea 352439384", //搜索字段的內容,空格可以分詞
"operator": "and" //and表示分詞並,都要有,還有個 默認是or 的關係
}
}
}
對應JAVA代碼
//查詢條件
QueryBuilder queryBuilder = QueryBuilders
.matchQuery("event", "BitSea 352439384").operator(Operator.AND);
單條件多字段
"query": {
{
"multi_match": {
"query": "搜索內容",
"fields": [ "字段1", "字段2" ]
}
}
}
java代碼
QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery("BitSea 352439384", "field1", "field2").operator(Operator.AND);
多條件多字段
"query": {
"bool": {
"should": [
{"match": { "event": "TEXT"}},
{"match": { "FIELD": "TEXT"}}
]
}
}
java代碼
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
queryBuilder.should(QueryBuilders.matchQuery("cname", keyword));
queryBuilder.should(QueryBuilders.matchQuery("industry", keyword));
2 Aggregations 聚合搜索
Aggregations我是用來去重,和查總數的。 它的方法比較多,很強大。
繼續以上面的來舉例子
去重
{
"query": {
"match": {
"event": {
"query": "BitSea 352439384",
"operator": "and"
}
}
},
"aggs": {
"name": { //去重自定義字段名
"terms": {
"field": "session_id",
"size": 10 //查詢數量的大小
}
}
},
"size": 1,
"from": 0
}
aggs和query是同級別的,上面這段的意思是,以session_id
字段對query的結果進行去重,然後查出前10條,來看JAVA代碼
//聚合篩選器,主要用來分頁和去重
AggregationBuilder aggregation = AggregationBuilders
.terms("去重字段名字").field("session_id").size(10);
//新建自定義查詢
QueryBuilder queryBuilder = QueryBuilders
.matchQuery("event", "BitSea 352439384").operator(Operator.AND);
查總數
"aggs": {
"count": { //查詢總數
"cardinality": {
"field":"session_id"
}
},
"測試": {
"terms": {
"field": "session_id",
"size":10,
"order":{
"_key": "desc"
}
}
}
}
java代碼
AggregationBuilder aggregation = AggregationBuilders.cardinality("count").field("session_id");
3. 查詢
查詢條件都梳理好了後,進行查詢,java代碼如下
SearchSourceBuilder ssb = new SearchSourceBuilder()
.query(queryBuilder) //組合查詢條件
.sort(sortBuilder) //排序條件
.aggregation(aggregation) //上面的去重
.aggregation(aggregation2); //上面的查總數
SearchRequest sr = new SearchRequest(new String[]{"cs_session_session_event_sharding_alias"}); //自己索引名稱
sr.source(ssb);
SearchResponse searchResponse = esClient.search("searchCluster", sr); //獲取查詢結果
獲取結果
Terms sessionIds = searchResponse.getAggregations().get("去重字段名字"); //括號裏是剛纔自己起的名字,總共有多少個SessionIds
Cardinality cardinality = searchResponse.getAggregations().get("總數");
System.out.println(cardinality.getValue());
for (Terms.Bucket entry : sessionIds.getBuckets()) {
String key = String.valueOf(entry.getKey()); //每個session
long docCount = entry.getDocCount(); //每個擊中多少條
System.out.println("key: "+key+ "doc_count:" + docCount);
}
特別注意
特殊字符
title+-&&||!(){}[]^\"~*?:\\
這些都需要轉義
你需要引用一個jar,lucene-queryparser,按自己的es版本去添加
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>5.4.1</version>
</dependency>
使用QueryParser.escape(String query)方法處理字符即可,
分詞器的使用
https://blog.csdn.net/ahwsk/article/details/101270300
題外話
ES7.x版本還支持 sql查詢,更推薦這中方式,但是比較複雜的邏輯有時候不太支持,具體的sql關鍵字可以到官網上查。