Elasticsearch筆記


拉呱,無論是當作全文檢索工具,還是僅僅當作NOSQL,Elasticsearch的性能,牛的沒法說!!!奈何和它相見恨晚

點擊進入官網

中文文檔

一. 使用場景

  • 全文檢索-像淘寶京東類似的網上商城,當我們在在搜索框搜索某個商品名稱時,網絡沒有問題的話,獲取響應的速度,幾乎和我們鍵盤起落的速度是一致的,這足以ES的魅力,億萬級別的搜索,秒秒鍾完事

  • 一個正規的項目運行過程中,日志的產出是源源不斷的,把日志的文本信息導入到ES,使用它的聚合功能輕松獲取我們關系的內容,結合Kibana做圖表分析,可視化日志記錄,動態分析

二. 基本概念

  • 2.1 什么是是全文檢索
    全文檢索就是計算機程序通過掃描文章中的每一個詞,對必要的詞建立一個索引(上篇博客我們使用ik分詞器,幫助es分詞),記錄下這個詞在文章中出現的位置和次數,這樣當用戶去查詢的時候,他可以根據索引極快的查找出相應的內容

稍微解釋下, 全文檢索可以片面的理解成是從敲代碼的人的角度上說的,假如你是用戶,你會關心什么全文檢索? 用戶關系的是搜索結果!那好,對我們敲代碼的來說,就是1.拿到用戶搜索框輸入的關鍵字送進ES (數據在存進es的時候,es對他們進行了索引)2.ES的程序會對關鍵字進行分詞,拿着這些碎片去ES中的索引庫里面的type中的field中匹配比對,那,那么多field,它和誰比對呢? 和標記上text屬性的字段比對)

另外要了解的內容1.全文檢索只處理文本不處理語義,2.全文檢索忽略英文的大小寫 3.結果可能不止一個,並且有相關得分

  • 2.2 與關系型數據庫名稱上的對比
mysql Elasticsearch
Database 數據庫 indices 索引
Table 數據表 type 類型
Row 行 document 文檔
Columns 列 Field 字段

其實大多數人都是先接觸的關系型數據庫,我也是,可能一開始感覺着好別扭,但是再回頭來看,好像他的名字比傳統的關系型數據庫名什么行啊列啊,更合理一些

  • 2.3 分片(shard)和副本(replica)

單機

通過圖片可以看到: 數據分成三部分,分別存放在三個分片里面,而且每個分片都有自己的副本,這樣就算是一台es,它同樣是分布式

二. 怎么玩?

這部分純屬扯皮了,不說語法,說一下我對它的感覺,首先呢, 為什么學它? 圖方便快速唄,大部分情況下,是需要使用它的全文檢索功能,但是總得有個下手點吧,不用說一開始都是環境配置一頓整,訪問個9200看到版本號,也算是開個頭了,然后呢? 先不用想他怎么檢索,怎么花里胡哨的檢索,我們得知道自己想檢索什么!先把數據給它,思路就來了,先去搞數據,下一步自然就是創建新的索引(數據庫),循環把我們的數據送進es的索引里面.到這里,也算是完成一半的任務了,下面就是使用人家提供好的api去索引庫,檢索就好了. 先有個大概的思路.想干什么,怎么干,往下學

三. 原生語法

  • elasticsearch采用的REST風格的api,也就是說,其實他就是一次http的請求

下面會有一些關鍵字 也就是json的 key部分,對我們來說,一般可以見名知意

3.1.1 創建索引庫

  • 請求方式: PUT
  • 請求路徑: /索引庫名
  • 請求參數: json
PUT /xiaowu1
{
  "settings": {
    "number_of_shards": 1
    , "number_of_replicas": 1
  }
}

成功的相應:

{
  "acknowledged": true,
  "shards_acknowledged": true,
  "index": "xiaowu1"
}

3.1.2 查看數據庫

  • 請求方式: GET
  • 格式: GET /索引庫名
GET /xiaowu1

響應:相關的源信息

{
  "xiaowu1": {
    "aliases": {},
    "mappings": {},
    "settings": {
      "index": {
        "creation_date": "1552653562807",
        "number_of_shards": "1",
        "number_of_replicas": "1",
        "uuid": "u0tMDD-pQXaHb77cTPorZA",
        "version": {
          "created": "6020499"
        },
        "provided_name": "xiaowu1"
      }
    }
  }
}

3.1.3 刪除索引庫

  • 請求方式: DELETE
  • 格式: DELETE /索引庫名

3.2.1 配置映射

在玩搜索之前我們要思考如何定義文檔的,如文檔包括哪些字段,這些字段是否保存,是否索引,是否分詞等等, 實際上就像是在描述我們數據庫中的一張表,有哪些列,列是什么類型的,是主鍵不?自增長不?

以后看到"mappings":{} 就像查看關系型數據庫中對整張表的定義一樣

  • 請求方式: PUT
  • 格式: PUT /索引庫名/_mapping/類型名
PUT /xiaowu/_mapping/goods
{
  "properties": {      ---屬性關鍵字
    "name":{           ---name為字段名,可以不止一個,就像數據庫中的列,你開心,多少個都行
      "type": "text",  ---類型常用:integer,long,text,object,date,short,string,float 
      "index": true,   ---是否索引  默認true
      "store": false,   ---是否存儲  默認false
      "analyzer": "ik_max_word" ---是否分詞
    },
     "images": {
      "type": "keyword",  
      "index": "false"
    },
    "age": {
      "type": "float"
    }
  }
}

1 .字符串類型有兩種

  • text : 可檢索
  • keyword : 不可檢索

2 .數值類型

  • 基本數值類型: long ,float,byte,double...
  • 浮點數高精度類型: scaled_float
    • 它需要我們指定一個精度因子,比如10,100,es把真實值乘以這個精度因子存儲,取出后還原,(商品價格)
  1. 日期類型:
  • Date
  1. 存儲對象
{girl:{name:"張三",age:23}

而是會把它處理成 girl.namegirl.age

5 .store

  • 表示,是否將數據額外存儲,意思是,如果不存儲,用戶就搜索不出來
  • 在solr中如果為store設為false,那么用戶就搜索不出來這個字段
  • 但是elasticsearch中,並不用store的值控制是否可以被搜索出來,即便他是false,用戶仍然可以搜索出結果,原因是elasticsearch的底層,在創建文檔時,會將文檔的原始數據備份保存到一個叫 _source的屬性中,而我們可以通過過濾_source選擇那些需要顯示,那些不需要顯示,這樣如我們把store的值設置為ture它就會多儲存一份,得不償失(store相當於作廢了)

3.2.2 向已經存在的索引庫中添加數據(不一定要指定ID)

  • 請求方式: POST
  • 格式: POST /索引庫名/類型名{}
POST /changwu/item/
{
    "title":"小米手機",
    "price":2699.00
}

響應:

{
  "_index": "changwu",
  "_type": "item",
  "_id": "Pj6bgWkB3eQnUSvRfoa2",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 5,
  "_primary_term": 6
}

id,是自動生成的當前數據的標識,我們還可以指定

POST /changwu/item/2

3.2.3 基本查詢

  • 請求方式: GET
GET /索引庫名/_search
{
  "query": {
    "查詢類型":{
      "查詢條件": "條件值"
    }
  }
}
  • query是Elasticsearch內置的一個對象,里面有不同的查詢屬性

使用,SpringDataElasticsearch玩復雜查詢的時候,免不了會BuildQueryXXX

  • 查詢類型:
    • match_all 查詢所有
    • match
    • term
    • range
  • 查詢條件根據類型的不同而不同,(就像關系型數據庫中表的字段不同...)

3.2.4 匹配查詢 match

or 關系

match類型查詢,會把查詢條件進行分詞,然后再查詢,詞條之間是or關系,按照相關性得分排序

GET /goods/_search
{
  "query": {
    "match":{
      "price": 269900
    }
  }
}

and關系

很多情況下我們希望更精確的查找,於是我們使用 and關系

GET /xiaowu/_search
{
     "query":{
       "match":{
         "title":{
            "query":"米手機",
            "operator":"and"
         }
       }
     }
}

這樣他在分詞的時候,米--手機同時都匹配上才會顯示出結果!

假設有這樣一種情況,用戶給定的條件分詞后,有五個詞,但是其中的四個是在描述他想要搜索的內容,如果使用or,毫無疑問,一大堆雜七雜八的東西被查詢出來,如果使用and,es很可能把那個目標文檔排除,那該怎么辦呢?看下面!

  • match支持使用minimum_should_match 最小匹配參數,通常設置為一個百分數
GET /xiaowu/_search
{
     "query":{
       "match":{
         "title":{
            "query":"米手機",
            "minimum_should_match":"75%"
         }
       }
     }
}

意思是,用戶輸入的詞條滿足75%的匹配程,我就認為是匹配上了, ---用戶輸入的檢索條件,被分解為三個詞,3*0.75=2.25 也就是說,這三個詞,至少有兩個是匹配上的,es就認為匹配成功

3.2.5多字段查詢 muti_match

  • muti_match和match一樣,但是不同的是它可以同時在多個字段中檢索
GET /xiaowu/_search
{
     "query":{
       "multi_match":{
            "query":"米",
            "fields":["title"]
       }
     }
}

他的fields接受一個字段數組

3.2.6 詞條查詢(term)

  • 和前面的查詢條件不同的是term,它被用作精確查詢,比如數字,時間,布爾,和字段屬性為keyword類型的關鍵字
GET /xiaowu/_search
{
   "query": {
     "term": {
       "price": {
         "value": "1888"
       }
     }
   }
}

3.2.7 多詞條精確匹配

  • 和term一樣的精確匹配,但是不同的是它支持同時使用多個詞條進行精確匹配,如果只要索引庫中的文檔包含指定值中的任意一個,都算作滿足條件

3.3.1 結果過濾

 默認情況下,elasicsearch在搜索的結果在,會把文檔保存在_source里面的所有字段都返回,如果我們想獲取里面的部分結果,添加_soure過濾

GET /xiaowu/_search
{
  "_source": ["過濾字段"], 
   "query": {
     "term": {
       "price": {
         "value": "1888"
       }
     }
   }
}
  • 另外,_source里面還有兩個屬性
    • "includes":[想顯示的字段]
    • "excludes":[不想顯示的字段]

解讀查詢結果:

{
  "took": 1,    ----花費時長,單位毫秒
  "timed_out": false,  ----是否超時
  "_shards": {      --- 分片信息
    "total": 1,    
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {     --- 命中的結果
    "total": 1, --- 結果總數
    "max_score": 4.765019, ---相關性的最高得分
    "hits": [      --- 搜索結果的對象數組
      {
        "_index": "goods",   ---  索引
        "_type": "docs",     --- 類型
        "_id": "180",        ---  唯一id
        "_score": 4.765019,  ---文檔得分
        "_source": {            --- 文檔的數據源,(前面說過,結果都在_source里面)
          "id": 180,
          ...
          }
  • 在所有的index里面查詢指定的字段
GET _search
{
  "query": {
   "match": {
     "title": "小米2手機"
   }
  }
}

3.4.1 智能判斷

  • 新增屬性的時候,可以添加新的字段
POST /xiaowu/goods/
{
  "title":"es666",
  "hehe":true
  
}

查詢結果:

{
        "_index": "xiaowu",
        "_type": "goods",
        "_id": "Qz69gWkB3eQnUSvRC4ah",
        "_score": 1,
        "_source": {
          "title": "es666",
          "hehe": true
        }

查看映射

{
  "xiaowu": {
    "mappings": {
      "goods": {
        "properties": {
          "age": {
            "type": "float"
          },
          "hehe": {
            "type": "boolean"
          },
          "images": {
            "type": "keyword",
            "index": false
          },
          "name": {
            "type": "text",
            "store": true,
            "analyzer": "ik_max_word"
          },
          "price": {
            "type": "float"
          },
          "title": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      }
    }
  }
}

這樣看,其實我們在上面配置的映射關系就沒有必要了,Elasticsearch會智能化的推斷出字段的type,比如true它推斷為boolean, 但是有問題的是title 它推斷為 text ,title.keyword是 keyword類型

3.5.1 修改數據(指明ID)

把上面的POST轉變成PUT就是修改

  • id對應的文檔存在則修改
  • id對應的文檔不存在則新增

3.6.1 刪除數據

語法: DELETE /索引庫名/類型名/id

3.7.1 高級玩法-布爾組合

看得懂,會使用Elasticsearch的高級玩法很重要,這關系着,能不能理解如何使用它的原生api進行高級查詢

  • 布爾組合,結合了其他的查詢,實現了這樣的功能, -- 我的搜索結果中,一定含有誰(must),一定不含有誰(must_not),可能含有誰(should)
GET /xiaowu/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "title": "米"
          }
        }
      ],
      "must_not": [
        {
          "match": {
            "title": "大"
          }
        }
      ],
     "should": [
       {
         "match": {
           "price": "999"
         }
       }
     ]
    }
  }
}

3.7.2 高級玩法--范圍查詢range

  • range實現的是查詢出滿足某個區間的結果
GET /xiaowu/_search
{
  "query": {
    "range": {
      "FIELD": {
        "gte": 10,
        "lte": 20
      }
    }
  }
}
關鍵字 含義
gte 大於等於
lte 小於等於
gt 大於
lt 小於

3.7.3 模糊查詢---fuzzy

模糊查詢很人性化,它允許用戶在編輯的條件有拼寫錯誤,但是出現偏差的編輯差距不得超過2

GET /xiaowu/_search
{
  "query": {
    "fuzzy": {
      "title": {
       "value": "appla",
       "fuzziness": 1
       }
    }
  }
}
  • 這樣查詢是可以查詢出apple的
  • "fuzziness": 限定編輯距離

3.7.4 過濾---filter

  • 1.有條件查詢進行過濾

查詢就會影響文檔的相關性得分,假如我們只是想在現有的查詢基礎上,根據需求過濾下一些結果,卻不想影響文檔的相關性得分的話filter就派上用場了

GET /changwu/_search
{
    "query":{
        "bool":{
        	"must":{ "match": { "title": "小米手機" }},
        	"filter":{
                "range":{"price":{"gt":2000.00,"lt":3800.00}}
        	}
        }
    }
}

filter中還可以在bool組合過濾

  • 2.無條件查詢進行過濾

如果一次查詢只有過濾,沒有查詢條件,不希望進行評分,我們可以使用constant_score

GET /changwu/_search
{
    "query":{
        "constant_score":   {
            "filter": {
            	 "range":{"price":{"gt":2000.00,"lt":3000.00}}
            }
        }
}

3.7.5 --- 排序 sort

排序sort和query是有先后順序的,先query,再排序

  • 單字段排序
GET /changwu/_search
{
  "query": {
    "match": {
      "title": "手機"
    }
  },
  "sort": [
    {
      "price": {
        "order": "asc"
      }
    }
  ]

}
  • 多字段排序

看上面的sort后面的條件,是個數組,因此我們可以寫條件,按多個字段進行排序


聚合:aggregations

  • 基本概念,兩個新概念,在Elasticsearch中的聚合分為兩個部分,聚合為 桶bucket度量
    • 桶就像mysql中的分組查詢,比如說學號相同,姓名相同的肯定是同一個人,我們就把它當成一組,在這里就是一個桶
    • 度量--以每個桶為基礎,做運算

當然Elasticsearah里面分桶的方式很多

  • Terms Aggregation:根據詞條內容分組,詞條內容完全匹配的為一組
  • Range Aggregation:數值和日期的范圍分組,指定開始和結束,然后按段分組,這個范圍要手動告訴他,0-10 10-15 15-30等
  • Histogram Aggregation:根據數值階梯(柱狀圖)分組,與日期類似, 告訴他一個段就行了,她會自動的分組
  • Date Histogram Aggregation:根據日期階梯分組,例如給定階梯為周,會自動每周分為一組

常用的度量方法:

  • Avg Aggregation:求平均值
  • Max Aggregation:求最大值
  • Min Aggregation:求最小值
  • Percentiles Aggregation:求百分比
  • Stats Aggregation:同時返回avg、max、min、sum、count等
  • Sum Aggregation:求和
  • Top hits Aggregation:求前幾
  • Value Count Aggregation:求總數

es中進行過濾,排序,聚合的字段,不能被分詞!!!!*

GET /cars/_search
{
  "size": 0,
  "aggs": {
    "popular_brand": {
      "terms": {
        "field": "color"
      },
      "aggs": {
        "priceAvg": {
          "avg": {
              "field": "price"
          }
        }
      }
    }
  }
}

一般都是先聚為桶,然后在桶的基礎上進行度量

四.SpringDataElsticsearch

SpringDataElasticsearch官方文檔地址

2.png

這是原來畫的圖,JEST直接放棄了,讓我們自己拼接json串,簡直只有難受

終於到編碼階段,這部分相比前面的原生api看起來就好受多了,Spring一整合,啥東西都簡單的只剩下兩件事,1,寫個配置文件,2.用它的方法,玩他的注解--, 當然我現在回顧學習的整個過程,最重要的是還是那句話,不要忘記了自己的需求,不然學着學着容易迷失,不知道自己想干啥,對於Elasticsearch吧先覺的它啥都能干,又覺得它啥也干不了,這是個很尷尬的事情! 那,我用它做全文檢索,我就得去搞明白 知道下面那幾件事

  1. 怎么搭建起開發環境,使我的java代碼和ES交互
  2. spring整合它嘛,提供了哪些注解,表示我的javaBean是個document對象
  3. 如何建立索引庫
  4. 基本的CRUD
  5. 花里胡哨的查詢方法

下面挨個做這幾件事!

4.1 搭建開發環境

坐標

 <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

配置文件(java和它的交互走的是tcp協議)

spring:
  application:
    name: search-service
  data:
    elasticsearch:
      cluster-nodes: 192.168.43.150:9300
      cluster-name: elasticsearch

啟動類

4.1 實體類及注解

實體類在java中就像是接盤俠,啥樣的東東,它都有能給接下來,看完了下面的注解,就知道了如何把數據存進es認識的實體類,准備把他們存在索引庫

import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;


@Data
@Document(indexName="changwu",type = "item",shards = 1)
public class Item {

    @Id
    @Field(type=FieldType.Long)
    Long id;

    @Field(type = FieldType.Text,analyzer = "ik_smart")
    String title; //標題

    @Field(type=FieldType.Keyword,index = true)
    String category;// 分類

    @Field(type=FieldType.Keyword)
    String brand; // 品牌

    @Field(type=FieldType.Double)
    Double price; // 價格

    @Field(type=FieldType.Keyword,index = false)
    String images; // 圖片地址
    
    // 指定存儲時和檢索時使用的分詞器是同一個
    // index=true 表示索引
    // 是否索引, 就是看這個字段是否能被搜索, 比如: 如果對整篇文章建立了索引,那么從文章中任意抽出一段來,都可以搜索出這個文章
    // 是否分詞, 就是表示搜索的時候,是整體匹配還是單詞匹配  比如: 如果不分詞的話,搜索時,一個詞不一樣,都搜索不出來結果

    // 是否存儲, 就是,是否在頁面上展示 , 但是在es中默認字段值已經存儲在_source 字段里, 也是能檢索出原始字段的
    @Field(index = true, store = true,type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
    private String title;

    /**
     * analyzer 存進去的時候,按這個分詞
     * searchAnalyzer: 搜索時,按這個分詞
     */
    @Field(index = true, store = true, type = FieldType.Text ,analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
    private String content;

    @Field(index = true,type = FieldType.Keyword)
    private String state;

}

  • @Document
  1. 作用在類,標記實體類為文檔對象
    • indexName:對應索引庫名稱---- 數據庫名
    • type:對應在索引庫中的類型---- 表名
    • shards:分片數量,默認5
      -replicas:副本數量,默認1
  • @Id
  1. 作用在成員變量id上
    • 標記一個字段作為id主鍵(這個id別寫錯了,不然程序都啟動不起來)
  • @Field
  1. 作用在成員變量,標記為文檔的字段,並指定字段映射屬性:
    • type:字段類型,取值是枚舉:FieldType
    • index:是否索引,布爾類型,默認是true
    • store:是否存儲,布爾類型,默認是false
    • analyzer:分詞器名稱

另外不要忘記了它的智能推斷,如果我們不在字段上添加@Field,他根據值的類型進行推斷

比如: 下面三個都會被推斷為long類型,

private Long cid3;//  
private Date createTime;//  
private List<Long> price;//  

4.2 創建索引庫

索引庫的創建放到text里面就ok了

  • 使用的是ElasticsearchTemplate,Spring一直都是這樣,整合完了,給你個模板

創建索引,添加映射,刪除索引

template.createIndex(Goods.class);
 
template.putMapping(Goods.class);

template.deleteIndex()

4.3 基本的CRUD

SpringData的強大之后就是,我們不再去寫dao層了,她會通過反射給我們寫好,有點Mybatis里面的通用mapper的意思,但是它更強大,---你給方法名它自動的生成方法

public interface GoodsRepository extends ElasticsearchRepository<Goods,Long> {}

使用 repository點一下,findXX saveXXX, deleteXXX全出來了,不再細說

另外:
點擊進入如何自定義方法,Spring給實現

如果可以看懂原生的語法,那么對他的使用就不多說了...就是無腦使用

到了這,就知道了如何把通過java代碼,對索引庫里面的數據進行簡單的增刪改查

4.4 着重看一下如何進行繁雜查詢

真正使用es的時候,Repository里面的方法可以滿足大部分的功能,但是聚合,過濾的話,只能使用原生的API

假設我們有下面的需求: 前端把用戶需要搜索的信息收集起來了--全文檢索

  • 全文檢索
/**
 * 全文檢索
 */
@Test
public void textQuery(){

    //創建查詢構建器
    NativeSearchQueryBuilder QueryBuilder = new NativeSearchQueryBuilder();

    /**
     * 給查詢構造器添加條件
     *   1. 它仍然需要的是一個  QueryBuilder ,通過QueryBuilders里面的靜態方法創建,間接繼承了QueryBuild
     *   2. 可也看到,基本上所有常用的條件查詢都有了, bool , 詞條term , match , 模糊查詢 fuzzy
     *   3. 我們也可以抽出來一個方法, 方法里使用bool查詢, 他支持先添加查詢,緊接着過濾,  還記不記得那個  match{},filter:{}
     *    3.1 注意區分開結果過濾_source 和 filter
     *
     *         matchQuery     @Param field
     *         matchQuery     @Param field的值
     *   */
    QueryBuilder.withQuery(QueryBuilders.matchQuery("title","小米"));

    /**
     * 結果過濾
     * @Param : SourceFilter  ,但是它是和接口,於是我用它唯一的實現類
     */
    QueryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{"title","price"},null));

    /**
     * 排序
     */
    QueryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));

    /**
     * 分頁
     *  原生的api使用下面兩個字段控制
     *  "from": 0,
     *  "size":10
     *  但是注意,他是的第一頁是0
     * @Param : Pageable 他是個接口,我們使用它的實現類  PageRequest(靜態方法of)
     */
    QueryBuilder.withPageable(PageRequest.of(1,10));

    Page<Goods> result = repository.search(QueryBuilder.build());  //它仍然需要的是一個QueryBuilder , 通過構造器.build()構建出來

    //解析結果
    long elements = result.getTotalElements();
    int totalPages = result.getTotalPages();
    List<Goods> content = result.getContent();
}


/**
 * 創建基本的查詢條件
 * 創建布爾查詢,
 *  一部分當作查詢條件(must)
 *  一部分當作過濾條件(filter)
 * @param searchRequest
 * @return QueryBuilder 給QueryBuild.withQuery()使用
 */
private QueryBuilder buildBasicQuery(SearchRequest searchRequest) {
    //創建布爾查詢
    BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
    //查詢條件
    queryBuilder.must(QueryBuilders.matchQuery("字段名",字段值));

    if(過濾條件){
    /*
    *把處理好的字段,傳給過濾器 過濾
    *@param name  The name of the field
    *@param value The value of the term
    */ 
    queryBuilder.filter(QueryBuilders.termQuery(字段名,字段值));
    }
return  queryBuilder;
}


  • 聚合查詢

3.png

 /**
   * 聚合查詢
   */
@Test
public void textAgg(){

    //同樣少不了 查詢構造器
    NativeSearchQueryBuilder QueryBuilder = new NativeSearchQueryBuilder();

    /**
     * 添加聚合add, 可以聚合多次
     * @Param AbstractAggregationBuilder 它間接繼承與 AggregationBuilder 我們下面的工具類
     *
     * AggregationBuilders下面基本上涵蓋了我們所有的聚合方式
     */
    QueryBuilder.addAggregation(AggregationBuilders.terms("popular_brand").field("brand"));

    /**
     * 推薦使用和這個,支持聚合查詢,並返回帶聚合的結果
     * @Param :SearchQuery
     * @Param :Class<T>
     * @Return:
     */
    AggregatedPage<Goods> result = template.queryForPage(QueryBuilder.build(), Goods.class);

    /**
     * 解析聚合
     *
     */
    Aggregations aggregations = result.getAggregations();
    // 獲取指定名稱 聚合
    //Aggregations agg = aggregations.get("popular_brand");
    StringTerms agg = aggregations.get("popular_brand");

    /**
     * 問題來了,  不存在 agg.getBuckets()
     * 原因看上面的圖,是 Aggregations是個頂級接口,
     */
    List<StringTerms.Bucket> buckets = agg.getBuckets();

    //遍歷buckets
    for (StringTerms.Bucket bucket : buckets) {
        System.out.println(bucket.getKeyAsString());
        System.out.println(bucket.getDocCount());
    }

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM