ElasticSearch搜索引擎
文章目錄
學習目標
- 理解elasticsearch索引結構和數據類型,掌握IK分詞器的使用
- 掌握索引的常用操作(使用Kibana工具)
- 掌握javaRest高級api
- 完成數據批量導入
1.ElasticSearche
1.1 全文檢索
如何能正確的顯示出用戶想要的商品,並進行合理的過濾,儘快促成交易,是搜索系統要研究的核心。面對這樣複雜的搜索業務和數據量,使用傳統數據庫搜索就顯得力不從心,一般我們都會使用全文檢索技術。 常見的全文檢索技術有 Lucene、solr 、elasticsearch 等。
1.2 索引結構
下邊黑色部分是物理結構,上邊黃色部分是邏輯結構,邏輯結構也是爲了更好的去描述工作原理及去使用物理結構中的索引文件。
邏輯結構部分是一個倒排索引表:
1、將要搜索的文檔內容分詞,所有不重複的詞組成分詞列表。
2、將搜索的文檔最終以Document方式存儲起來。
3、每個詞和docment都有關聯。
如下:
現在,如果我們想搜索 quick brown
,我們只需要查找包含每個詞條的文檔
兩個文檔都匹配,但是第一個文檔比第二個匹配度更高。如果我們使用僅計算匹配 詞條數量的簡單 相似性算法 ,那麼,我們可以說,對於我們查詢的相關性來講,第一個 文檔比第二個文檔更佳。
1.3 ElasticSearch
1.3.1 ElasticSearch介紹
ElasticSearch是一個基於Lucene的搜索服務器,提供了一個分佈式多用戶能力的全文搜索引擎,提供了RestFul web 接口,便於操作使用。用java開發的,開源免費的。
官網地址:https://www.elastic.co/cn/products/elasticsearch
GitHub:https://github.com/elastic/elasticsearch
學習使用的是elasticsearch 6.5.2
優點:
- 可作爲大型分佈式幾圈技術,處理PB級別數據,服務大公司,同時也可以允許在單機上。
- 把全文檢索、數據分析以及分佈式技術合併在一起。形成獨一無二的ES;
- 開箱即用,部署簡單
- 全文檢索、同義詞處理、相關排名、複雜數據分析、海量數據的近實時處理
是Elasticsearch與MySQL數據庫邏輯結構概念的對比
ElasticSearch | 關係型數據庫MySQL |
---|---|
索引(Index) | 數據庫(DataBases) |
類型(Type) | 表(Table) |
文檔(Document) | 行(Row) |
一般我們會這樣操作:一個索引庫裏面只有一種類型。
下載地址:https://www.elastic.co/cn/downloads/past-releases/
無需安裝,解壓安裝包後即可使用
在命令提示符下,進入ElasticSearch安裝目錄下的bin目錄,執行命令
elasticsearch
即可啓動.
在瀏覽器中輸入:http://127.0.0.1:9200既可以看到輸出結果。
{
"name" : "lB-loiZ",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "p_DyfvICQuS8fGcEpDUZjw",
"version" : {
"number" : "6.5.2",
"build_flavor" : "default",
"build_type" : "zip",
"build_hash" : "9434bed",
"build_date" : "2018-11-29T23:58:20.891072Z",
"build_snapshot" : false,
"lucene_version" : "7.5.0",
"minimum_wire_compatibility_version" : "5.6.0",
"minimum_index_compatibility_version" : "5.0.0"
},
"tagline" : "You Know, for Search"
}
1.4 使用postman操作索引庫
1.4.1 新建文檔
使用postman測試:以post方式提交 http://127.0.0.1:9200/testindex/doc
body:
{
"name":"測試商品",
"price":123
}
POST請求方式:http://localhost:9200/索引名稱/索引類型/ 參數爲json類型
如果索引、類型不存在elasticsearch會自動進行創建。
返回結果:
{
"_index": "testindex",//表示索引庫
"_type": "doc",//類型爲doc
"_id": "QXDM724BgQEvCDLHV5pO",
"_version": 1, //該id下記錄數據更改次數.
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
_id是由系統自動生成的。
elasticsearch可以在不建立結構下直接加入數據,添加數據之後,
可以根據添加的數據的類型,自動創建索引庫、類型以及相應的字段。
1.4.2 查詢文檔
Get請求:http://localhost:9200/testindex/doc/_search
返回結構
{
"took": 78,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 4,
"max_score": 1.0,
"hits": [
{
"_index": "testindex",
"_type": "doc",
"_id": "RHDX724BgQEvCDLH2pqw",
"_score": 1.0, //分值、匹配度 _search 簡單搜索。
"_source": {
"name": "蘋果電腦",
"price": 5500
}
},
{
"_index": "testindex",
"_type": "doc",
"_id": "QXDM724BgQEvCDLHV5pO",
"_score": 1.0,
"_source": {
"name": "測試商品",
"price": 123
}
},
{
"_index": "testindex",
"_type": "doc",
"_id": "Q3DX724BgQEvCDLHs5rc",
"_score": 1.0,
"_source": {
"name": "蘋果手機",
"price": 3500
}
},
{
"_index": "testindex",
"_type": "doc",
"_id": "QnDX724BgQEvCDLHZpqb",
"_score": 1.0,
"_source": {
"name": "華爲手機",
"price": 1500
}
}
]
}
}
1.5 映射和數據類型
映射(Mapping)相當於數據表的表結構。ElasticSearch中的映射(Mapping)用來
定義一個文檔,可以定義所包含的字段以及字段的類型、分詞器及屬性等等。
映射可以分爲動態映射和靜態映射。
- 動態映射 (dynamic mapping):在關係數據庫中,需要事先創建數據庫,然後在
該數據庫實例下創建數據表,然後才能在該數據表中插入數據。而ElasticSearch中不需
要事先定義映射(Mapping),文檔寫入ElasticSearch時,會根據文檔字段自動識別類
型,這種機制稱之爲動態映射。
- 靜態映射 :在ElasticSearch中也可以事先定義好映射,包含文檔的各個字段及其類
型等,這種方式稱之爲靜態映射。
1.5.1 字符串類型
類型 | 描述 |
---|---|
text | 當一個字段是要被全文搜索的,比如Email內容、產品描述,應該使用 text類型。設置text類型以後,字段內容會被分析,在生成倒排索引以前,字符串會被分析器分成一個 一個詞項。text類型的字段不用於排 序,很少用於聚合。 |
keyword | keyword類型適用於索引結構化的字段,比如email地址、主機名、狀 態碼和標籤。如果字段需要進行過濾(比如查找已發佈博客中status屬性 爲published的文章)、排序、聚合。keyword類型的字段只能通過精確值搜索到。 |
1.5.2 整數類型
類型 | 取值範圍 |
---|---|
byte | -128~127 |
short | -32768~32767 |
integer | -231~231-1 |
long | -263~263-1 |
1.5.3 浮點類型
類型 | 取值範圍 |
---|---|
double | 64位雙精度浮點類型 |
float | 32位單精度浮點類型 |
half_float | 16位單精度浮點類型 |
scaled_float | 縮放類型的浮點數 |
1.5.4 date類型
日期類型表示格式可以是以下幾種:
(1)日期格式的字符串,比如 “2018-01-13” 或 “2018-01-13 12:10:30”
(2)long類型的毫秒數( milliseconds-since-the-epoch,epoch就是指UNIX誕生的UTC 時間1970年1月1日0時0分0秒)
(3)integer的秒數(seconds-since-the-epoch)
1.5.5 boolean 類型
邏輯類型(布爾類型)可以接受true/false
1.5.6 binary類型
二進制字段是指用base64來表示索引中存儲的二進制數據,可用來存儲二進制形式
的數據,例如圖像。默認情況下,該類型的字段只存儲不索引。二進制類型只支持
index_name屬性。
1.5.7 array類型
在ElasticSearch中,沒有專門的數組(Array)數據類型,但是,在默認情況下,任意一個字段都可以包含0或多個值,這意味着每個字段默認都是數組類型,只不過,數組類型的各個元素值的數據類型必須相同。在ElasticSearch中,數組是開箱即用的(out of box),不需要進行任何配置,就可以直接使用。
在同一個數組中,數組元素的數據類型是相同的,ElasticSearch不支持元素爲多個數據類型:[ 10, “some string” ],
常用的數組類型是:
(1)字符數組: [ “one”, “two” ]
(2)整數數組: productid:[ 1, 2 ]
(3)對象(文檔)數組: “user”:[ { “name”: “Mary”, “age”: 12 }, { “name”: “John”, “age”: 10 }],ElasticSearch內部把對象數組展開爲 {“user.name”: [“Mary”, “John”], “user.age”: [12,10]}
1.5.8 object類型
JSON天生具有層級關係,文檔會包含嵌套的對象
1.6 IK分詞器
1.6.1 默認中文分詞器
使用postman測試 post方式提交
http://127.0.0.1:9200/testindex/_analyze
//指定分詞器 :analyzer:chinese
{"analyzer": "chinese", "text": "java程序員" }
返回結果:
{
"tokens": [
{
"token": "java",
"start_offset": 0,
"end_offset": 4,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "程",
"start_offset": 4,
"end_offset": 5,
"type": "<IDEOGRAPHIC>",
"position": 1
},
{
"token": "序",
"start_offset": 5,
"end_offset": 6,
"type": "<IDEOGRAPHIC>",
"position": 2
},
{
"token": "員",
"start_offset": 6,
"end_offset": 7,
"type": "<IDEOGRAPHIC>",
"position": 3
}
]
}
默認的中文分詞是將每個字看成一個詞,所以需要安裝一箇中文分詞器來解決問題.IK中文分詞器。
1.6.2 IK中文分詞器
下載地址:https://github.com/medcl/elasticsearch-analysis-ik/releases 下載6.5.2版
(1)先將其解壓,將解壓後的elasticsearch文件夾重命名文件夾爲ik
(2)將ik文件夾拷貝到elasticsearch/plugins 目錄下。
(3)重新啓動,即可加載IK分詞器
IK分詞有兩種算法
- 最小切分
使用postman測試 post方式提交
http://localhost:9200/testindex/_analyze
{
"analyzer":"ik_smart",
"text":"java程序員"
}
返回結果:
{
"tokens": [
{
"token": "java",
"start_offset": 0,
"end_offset": 4,
"type": "ENGLISH",
"position": 0
},
{
"token": "程序員",
"start_offset": 4,
"end_offset": 7,
"type": "CN_WORD",
"position": 1
}
]
}
- 最細切分
使用postman測試 post方式提交
http://localhost:9200/testindex/_analyze
{
"analyzer":"ik_max_word",
"text":"java程序員"
}
返回結果:
{
"tokens": [
{
"token": "java",
"start_offset": 0,
"end_offset": 4,
"type": "ENGLISH",
"position": 0
},
{
"token": "程序員",
"start_offset": 4,
"end_offset": 7,
"type": "CN_WORD",
"position": 1
},
{
"token": "程序",
"start_offset": 4,
"end_offset": 6,
"type": "CN_WORD",
"position": 2
},
{
"token": "員",
"start_offset": 6,
"end_offset": 7,
"type": "CN_CHAR",
"position": 3
}
]
}
1.6.3 IK分詞器之自定義詞庫
在測試"傳智播客",
使用postman測試 post方式提交
http://localhost:9200/testindex/_analyze
{
"analyzer":"ik_max_word",
"text":"傳智播客"
}
返回結果:
{
"tokens": [
{
"token": "傳",
"start_offset": 0,
"end_offset": 1,
"type": "CN_CHAR",
"position": 0
},
{
"token": "智",
"start_offset": 1,
"end_offset": 2,
"type": "CN_CHAR",
"position": 1
},
{
"token": "播",
"start_offset": 2,
"end_offset": 3,
"type": "CN_CHAR",
"position": 2
},
{
"token": "客",
"start_offset": 3,
"end_offset": 4,
"type": "CN_CHAR",
"position": 3
}
]
}
默認的分詞並沒有識別“ 傳智播客”是一個詞。如果我們想讓系統識別“傳智播客”是一個詞,需要編輯自定義詞庫。
步驟:
(1)進入elasticsearch/plugins/ik/config目錄
(2)新建一個my.dic文件,編輯內容:
傳智播客
文本文件要使用UTF-8編碼格式
修改IKAnalyzer.cfg.xml(在ik/config目錄下)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 擴展配置</comment>
<!--用戶可以在這裏配置自己的擴展字典 -->
<entry key="ext_dict">my.dic</entry>
<!--用戶可以在這裏配置自己的擴展停止詞字典-->
<entry key="ext_stopwords"></entry>
<!--用戶可以在這裏配置遠程擴展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用戶可以在這裏配置遠程擴展停止詞字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
重新啓動elasticsearch,通過瀏覽器測試分詞效果
{
"tokens": [
{
"token": "傳智播客",
"start_offset": 0,
"end_offset": 4,
"type": "CN_WORD",
"position": 0
}
]
}
1.7 Kibana
1.7.1 Kibana介紹
Kibana 是一個開源的分析和可視化平臺,旨在與 Elasticsearch 合作。Kibana 提供
搜索、查看和與存儲在 Elasticsearch 索引中的數據進行交互的功能。開發者或運維人員
可以輕鬆地執行高級數據分析,並在各種圖表、表格和地圖中可視化數據。
1.7.2 Kibana安裝啓動
(1)解壓 資料\配套軟件\elasticsearch\kibana-6.5.2-windows-x86_64.zip
(2)如果Kibana遠程連接Elasticsearch ,可以修改config\kibana.yml
(3)執行bin\kibana.bat
(4)打開瀏覽器,鍵入http://localhost:5601 訪問Kibana
2.索引操作
2.1 創建索引與映射字段
語法
請求方式依然是PUT
PUT /索引庫名
{
"mappings": {
"類型名稱":{ //類似於數據庫中的不同表字段名:任意填寫 ,相當於表的名稱。
"properties": {
"字段名": {
"type": "類型",
"index": true,
"store": true,
"analyzer": "分詞器"//比如ik_max_word
}
}
}
}
- 類型名稱:類似於數據庫中的不同表字段名:任意填寫,可以指定許多屬性,例如:
- type:類型,可以是text、long、short、date、integer、object等
- index:是否索引,默認爲true ,比如商品圖片,就可以不用設置成索引進行搜索
- store:是否單獨存儲,默認爲false ,一般內容比較多的字段設置成true,可提升查詢性能
- analyzer:分詞器
#創建索引結構
PUT sku {
"mappings": {
"doc":{
"properties":{
"name":{
"type":"text",
"analyzer":"ik_smart"
},
"price":{
"type":"integer"
},
"image":{
"type":"text",
"index":false
},
"createTime":{
"type":"date"
},
"spuId":{
"type":"text"
},
"categoryName":{
"type":"keyword"
},
"brandName":{
"type":"keyword"
},
"spec":{
"type":"object"
},
"saleNum":{
"type":"integer"
},
"commentNum":{
"type":"integer"
}
}
}
}
}
把要查詢的信息進行建立索引。
sku id == _id //使用elasticsearch的自動創建的id
商品名稱 需要進行分詞 text
商品價格 integer
商品圖片 不需要索引 text
創建時間 data
spu id text
商品分類 keyword (需要進行聚合操作)
品牌 keyword
規格 object(數據庫中存儲的是一個json對象{"顏色":"紅色","網絡":"5G"},使用Object類型,在添加數據的時候也是使用json格式)
銷量 Integer
評價 text
響應結果
{
"acknowledged": true, //表示生成成功。
"shards_acknowledged": true,
"index": "sku"
}
2.2 文檔增加與修改
2.2.1 增加文檔自動生成ID
通過POST請求,可以向一個已經存在的索引庫添加數據
語法格式
POST 索引庫名/ 類型名
{
"key":"value"
}
比如:
### 插入文檔
POST sku/doc
{
"name":"小米手機",
"price":200000,
"spuId":101,
"createTime":"2019-05-01",
"brandName":"小米",
"categerName":"手機",
"saleNum":1203,
"commentNum":2356,
"spec":{
"網絡制式":"移動4G",
"屏幕尺寸":"4.5"
}
}
響應結果
{
"_index" : "sku",
"_type" : "doc",
"_id" : "C8nT9G4BM_AZ6-65IXJW",//在添加文檔的時候,不指定id,elasticsearch會自動生成
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
通過以下命令查詢sku索引的數據
GET sku/_search
響應結果
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 1.0,
"hits" : [
{
"_index" : "sku",
"_type" : "doc",
"_id" : "C8nT9G4BM_AZ6-65IXJW",
"_score" : 1.0,
"_source" : {
"name" : "小米手機",
"price" : 200000,
"spuId" : 101,
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手機",
"saleNum" : 1203,
"commentNum" : 2356,
"spec" : {
"網絡制式" : "移動4G",
"屏幕尺寸" : "4.5"
}
}
}
]
}
}
2.2.2 新增文檔指定ID
語法
PUT 索引庫名/類型/id值
{
"key":"value"
}
比如
###新增文檔指定id
PUT sku/doc/1
{
"name":"華爲手機",
"price":400000,
"spuId":"102",
"createTime":"2019-05-01",
"brandName":"華爲",
"categerName":"手機",
"saleNum":1403,
"commentNum":2656,
"spec":{
"網絡制式":"全網通",
"屏幕尺寸":"6.5"
}
}
相應結果
{
"_index" : "sku",
"_type" : "doc",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
再次使用GET sku/_search 得到的結果
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 1.0,
"hits" : [
{
"_index" : "sku",
"_type" : "doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"name" : "華爲手機",
"price" : 400000,
"spuId" : "102",
"createTime" : "2019-05-01",
"brandName" : "華爲",
"categerName" : "手機",
"saleNum" : 1403,
"commentNum" : 2656,
"spec" : {
"網絡制式" : "全網通",
"屏幕尺寸" : "6.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "C8nT9G4BM_AZ6-65IXJW",
"_score" : 1.0,
"_source" : {
"name" : "小米手機",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手機",
"saleNum" : 1203,
"commentNum" : 2356,
"spec" : {
"網絡制式" : "移動4G",
"屏幕尺寸" : "4.5"
}
}
}
]
}
}
修改文檔(可以更具id進行修改)
比如: 修改華爲手機的評論數
PUT sku/doc/1
{
"name":"華爲手機",
"price":400000,
"spuId":"102",
"createTime":"2019-05-01",
"brandName":"華爲",
"categerName":"手機",
"saleNum":1403,
"commentNum":12656,
"spec":{
"網絡制式":"全網通",
"屏幕尺寸":"6.5"
}
}
相應結果中的"result"變成"updated"
{
"_index" : "sku",
"_type" : "doc",
"_id" : "1",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}
可以使用 GET sku/_search 進行查看修改的結果。華爲手機的評論數發生改變。
2.3 *****
索引查詢 *****
基本語法
GET 索引庫名/_search
{
"query":{
"查詢類型":{
"查詢條件":"查詢條件值"
}
}
}
query
代表一個查詢對象,裏面可以有不同的查詢屬性
- 查詢類型
match_all
、match
、term(根據字段)
、range(根據區間)
、等。
- 查詢條件:查詢條件會根據類型的不同,寫法也有差異。比如
bool
、過濾查詢/分組查詢
2.3.1 查詢所有數據(match_all)
GET sku/_search
{
"query":{
“match_all”:{}
}
}
query
:代表查詢對象match_all
:代表查詢所有
上面查詢所有的簡化版寫法GET sku/_search
- took:查詢花費時間,單位是毫秒
- time_out:是否超時
- _shards:分片信息
- hits:搜索結果總覽對象
- total:搜索到的總條數
- max_score:所有結果中文檔得分的最高分
- -hits:搜索結果的文檔對象數組,每個元素是一條搜索到的文檔信息
- _index:索引庫
- _type:文檔類型
- _id:文檔id
- _score:文檔得分
- _source:文檔的源數據
2.3.2 匹配查詢(match)
查詢名稱包含手機
###查詢名稱包含手機
GET sku/_search
{
"query": {
"match": {
"name": "手機"
}
}
}
查詢結果
{
"took" : 23,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 3,
"max_score" : 0.6931472,
"hits" : [
{
"_index" : "sku",
"_type" : "doc",
"_id" : "DMnp9G4BM_AZ6-65jnKA",
"_score" : 0.6931472,
"_source" : {
"name" : "三星手機",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手機",
"saleNum" : 1203,
"commentNum" : 55455,
"spec" : {
"網絡制式" : "移動4G",
"屏幕尺寸" : "4.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "1",
"_score" : 0.2876821,
"_source" : {
"name" : "華爲手機",
"price" : 400000,
"spuId" : "102",
"createTime" : "2019-05-01",
"brandName" : "華爲",
"categerName" : "手機",
"saleNum" : 1403,
"commentNum" : 12656,
"spec" : {
"網絡制式" : "全網通",
"屏幕尺寸" : "6.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "C8nT9G4BM_AZ6-65IXJW",
"_score" : 0.2876821,
"_source" : {
"name" : "小米手機",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手機",
"saleNum" : 1203,
"commentNum" : 2356,
"spec" : {
"網絡制式" : "移動4G",
"屏幕尺寸" : "4.5"
}
}
}
]
}
}
查詢“小米電視”
看到結果爲小米電視、三星電視、小米手機三條結果,這是爲什麼呢?這是因爲在
查詢時,會先將搜索關鍵字進行分詞,對分詞後的字符串進行查詢,只要是包含這些字
符串的都是要被查詢出來的,多個詞之間是 or 的關係。
返回的結果中_score是對這條記錄的評分,評分代表這條記錄與搜索關鍵字的匹配度,
查詢結果按評分進行降序排序。 比如我們剛纔搜索“小米電視” ,那小米電視這條記錄的 評分是最高的,排列在最前面。
如果我們需要精確查找,也就是同時包含小米和電視兩個詞的纔可以查詢出來,這就需
要將操作改爲 and 關係:
### 精準查詢
GET sku/_search
{
"query": {
"match": {
"name": {
"query": "小米電視",
"operator":"and"
}
}
}
}
返回結果:
{
"took" : 18,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 1.3862944,
"hits" : [
{
"_index" : "sku",
"_type" : "doc",
"_id" : "Dsnu9G4BM_AZ6-65zXIP",
"_score" : 1.3862944,
"_source" : {
"name" : "小米電視",
"price" : 300000,
"spuId" : "105",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "電視",
"saleNum" : 32203,
"commentNum" : 455455,
"spec" : {
"網絡制式" : "移動4G",
"屏幕尺寸" : "4.5"
}
}
}
]
}
}
2.3.3 多字段查詢(multi_match)
### 多字段查詢
GET sku/_search
{
"query":{
"multi_match":{
"query":"小米",
"fields":["name","brandName","categoryName"]
}
}
}
會在name、brandName 、categoryName字段中查詢 小米
這個詞
2.3.4 詞條匹配(term)
term查詢被用於精確值 匹配,這些精確值可能是數字、時間、布爾或者那些未分詞的字
符串
###精準查詢
GET sku/_search
{
"query":{
"term":{
"price":200000
}
}
}
查詢結果
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 1.0,
"hits" : [
{
"_index" : "sku",
"_type" : "doc",
"_id" : "DMnp9G4BM_AZ6-65jnKA",
"_score" : 1.0,
"_source" : {
"name" : "三星手機",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手機",
"saleNum" : 1203,
"commentNum" : 55455,
"spec" : {
"網絡制式" : "移動4G",
"屏幕尺寸" : "4.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "C8nT9G4BM_AZ6-65IXJW",
"_score" : 1.0,
"_source" : {
"name" : "小米手機",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手機",
"saleNum" : 1203,
"commentNum" : 2356,
"spec" : {
"網絡制式" : "移動4G",
"屏幕尺寸" : "4.5"
}
}
}
]
}
}
2.3.5 多詞條匹配(terms)
terms 查詢和 term 查詢一樣,但它允許你指定多值進行匹配。如果這個字段包含了指定 值中的任何一個值,那麼這個文檔滿足條件:
###精準查詢
GET sku/_search
{
"query":{
"terms":{
"price":[100000,200000]
}
}
}
2.3.6 布爾組合(bool)
bool
把各種其它查詢通過 must (與)
、must_not (非
)、 should (或
)的方式進行
組合
查詢名稱包含手機的,並且品牌爲小米的。
#查詢名稱包含手機的,並且品牌爲小米的。
Get sku/_search
{
"query":{
"bool":{
"must":[
{"match":{"name":"手機"}},
{"term":{"brandName":"小米"}}
]
}
}
}
返回結果
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 0.87546873,
"hits" : [
{
"_index" : "sku",
"_type" : "doc",
"_id" : "DMnp9G4BM_AZ6-65jnKA",
"_score" : 0.87546873,
"_source" : {
"name" : "三星手機",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手機",
"saleNum" : 1203,
"commentNum" : 55455,
"spec" : {
"網絡制式" : "移動4G",
"屏幕尺寸" : "4.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "C8nT9G4BM_AZ6-65IXJW",
"_score" : 0.5753642,
"_source" : {
"name" : "小米手機",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手機",
"saleNum" : 1203,
"commentNum" : 2356,
"spec" : {
"網絡制式" : "移動4G",
"屏幕尺寸" : "4.5"
}
}
}
]
}
}
查詢名稱包含手機的,或者品牌爲小米的
#查詢名稱包含手機的,並且品牌爲小米的。
Get sku/_search
{
"query":{
"bool":{
"should":[
{"match":{"name":"手機"}},
{"term":{"brandName":"小米"}}
]
}
}
}
2.3.7 過濾查詢
過濾是針對搜索的結果進行過濾,過濾器主要判斷的是文檔是否匹配,不去計算和
判斷文檔的匹配度得分,所以過濾器性能比查詢要高,且方便緩存,推薦儘量使用過濾
器去實現查詢或者過濾器和查詢共同使用。
過濾品牌爲小米的記錄
Get sku/_search
{
"query":{
"bool":{
"filter": [
{"match":{"brandName":"小米"}}
]
}
}
}
結果
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 3,
"max_score" : 0.0,
"hits" : [
{
"_index" : "sku",
"_type" : "doc",
"_id" : "DMnp9G4BM_AZ6-65jnKA",
"_score" : 0.0,
"_source" : {
"name" : "三星手機",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手機",
"saleNum" : 1203,
"commentNum" : 55455,
"spec" : {
"網絡制式" : "移動4G",
"屏幕尺寸" : "4.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "Dsnu9G4BM_AZ6-65zXIP",
"_score" : 0.0,
"_source" : {
"name" : "小米電視",
"price" : 300000,
"spuId" : "105",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "電視",
"saleNum" : 32203,
"commentNum" : 455455,
"spec" : {
"網絡制式" : "移動4G",
"屏幕尺寸" : "4.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "C8nT9G4BM_AZ6-65IXJW",
"_score" : 0.0,
"_source" : {
"name" : "小米手機",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手機",
"saleNum" : 1203,
"commentNum" : 2356,
"spec" : {
"網絡制式" : "移動4G",
"屏幕尺寸" : "4.5"
}
}
}
]
}
}
2.3.8 分組查詢
按分組名稱聚合查詢,統計每個分組的數量
#分組查詢
GET sku/_search
{
### aggs 表示分組
"aggs": {
"sku_category": { //分組展示的名稱
"terms": {
"field": "price"
}
}
}
}
展示結果
{
"took" : 7,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 5,
"max_score" : 1.0,
"hits" : [
{
"_index" : "sku",
"_type" : "doc",
"_id" : "DMnp9G4BM_AZ6-65jnKA",
"_score" : 1.0,
"_source" : {
"name" : "三星手機",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手機",
"saleNum" : 1203,
"commentNum" : 55455,
"spec" : {
"網絡制式" : "移動4G",
"屏幕尺寸" : "4.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "Dsnu9G4BM_AZ6-65zXIP",
"_score" : 1.0,
"_source" : {
"name" : "小米電視",
"price" : 300000,
"spuId" : "105",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "電視",
"saleNum" : 32203,
"commentNum" : 455455,
"spec" : {
"網絡制式" : "移動4G",
"屏幕尺寸" : "4.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "Dcnq9G4BM_AZ6-65B3Is",
"_score" : 1.0,
"_source" : {
"name" : "三星電視",
"price" : 400000,
"spuId" : "103",
"createTime" : "2019-05-01",
"brandName" : "三星",
"categerName" : "手機",
"saleNum" : 12203,
"commentNum" : 255455,
"spec" : {
"網絡制式" : "移動4G",
"屏幕尺寸" : "4.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"name" : "華爲手機",
"price" : 400000,
"spuId" : "102",
"createTime" : "2019-05-01",
"brandName" : "華爲",
"categerName" : "手機",
"saleNum" : 1403,
"commentNum" : 12656,
"spec" : {
"網絡制式" : "全網通",
"屏幕尺寸" : "6.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "C8nT9G4BM_AZ6-65IXJW",
"_score" : 1.0,
"_source" : {
"name" : "小米手機",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手機",
"saleNum" : 1203,
"commentNum" : 2356,
"spec" : {
"網絡制式" : "移動4G",
"屏幕尺寸" : "4.5"
}
}
}
]
},
"aggregations" : {
"sku_category" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : 200000,
"doc_count" : 2
},
{
"key" : 400000,
"doc_count" : 2
},
{
"key" : 300000,
"doc_count" : 1
}
]
}
}
}
多個分組查詢
GET sku/_search
{
"size": 0, ###如果size:0 表示不用展示hits:[] 裏面的數據了
"aggs": {
"sku_category": {
"terms": {
"field": "price"
}
},
"sku_brand": {
"terms": {
"field": "brandName"
}
}
}
}
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 5,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"sku_category" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : 200000,
"doc_count" : 2
},
{
"key" : 400000,
"doc_count" : 2
},
{
"key" : 300000,
"doc_count" : 1
}
]
},
"sku_brand" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "小米",
"doc_count" : 3
},
{
"key" : "三星",
"doc_count" : 1
},
{
"key" : "華爲",
"doc_count" : 1
}
]
}
}
}
3.使用Java操作索引
3.1 簡介
elasticsearch 存在三種Java客戶端。
- Transport Client
- Java Low Level Rest Client(低級rest客戶端)
- Java High Level REST Client(高級rest客戶端)
這三者的區別是:
- TransportClient沒有使用RESTful風格的接口,而是二進制的方式傳輸數據。
- ES官方推出了Java Low Level REST Client,它支持RESTful。但是缺點是因爲TransportClient的使用者把代碼遷移到Low Level REST Client的工作量比較大。
- ES官方推出Java High Level REST Client,它是基於Java Low Level REST Client的封裝,並且API接收參數和返回值和TransportClient是一樣的,使得代碼遷移變得容易 並且支持了RESTful的風格,兼容了這兩種客戶端的優點。強烈建議ES5及其以後的版本使用Java High Level REST Client。
準備工作:新建工程,引入依賴
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.5.3</version>
</dependency>
3.2 Java操作ElasticSearch中的Index索引
3.2.1 新增和修改數據
插入單條數據:
HttpHost : url地址封裝
RestClientBuilder: rest客戶端構建器
RestHighLevelClient: rest高級客戶端
IndexRequest: 新增或修改請求
IndexResponse:新增或修改的響應結果
import org.apache.http.HttpHost;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import java.util.HashMap;
import java.util.Map;
public class Demo1 {
public static void main(String[] args) {
//1.鏈接rest接口
HttpHost http = new HttpHost("127.0.0.1", 9200, "http");
RestClientBuilder restClientBuilder = RestClient.builder(http);
RestHighLevelClient restHighLevelClient = new RestHighLevelClient(restClientBuilder);
//2.封裝請求對象
IndexRequest indexRequest = new IndexRequest("sku", "doc", "3");
Map skuMap = new HashMap();
skuMap.put("name", "華爲p30");
skuMap.put("name", "華爲p30pro");
skuMap.put("brandName", "華爲");
skuMap.put("categoryName", "手機");
skuMap.put("price", 1010221);
skuMap.put("createTime", "2019-05-01");
skuMap.put("saleNum", 101021);
skuMap.put("commentNum", 10102321);
//spec在索引庫的類型爲Object ,在java代碼中我們使用map進行封裝spec,然後在封裝到外面一層的map。
Map spec = new HashMap();
spec.put("網絡制式", "移動4G");
spec.put("屏幕尺寸", "5");
skuMap.put("spec", spec);
indexRequest.source(skuMap);
//3.獲取請求結果
try{
IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
//執行狀態
int status = indexResponse.status().getStatus();
System.out.println(status);
}catch (Exception e){
e.printStackTrace();
}
//關閉資源流
}
}
如果ID不存在則新增,如果ID存在則修改。
批處理請求
批處理請求:
BulkRequest: 批量請求(用於增刪改操作)
BulkResponse:批量請求(用於增刪改操作)
import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import java.util.HashMap;
import java.util.Map;
public class Demo2 {
public static void main(String[] args) {
//1.連接rest接口
HttpHost http = new HttpHost("127.0.0.1", 9200, "http");
RestClientBuilder builder = RestClient.builder(http);
//rest構建器
RestHighLevelClient restHighLevelClient = new RestHighLevelClient(builder);
//高級客戶端對象
// 2.封裝請求對象
BulkRequest bulkRequest = new BulkRequest();
IndexRequest indexRequest = new IndexRequest("sku", "doc", "4");
Map skuMap = new HashMap();
skuMap.put("name", "華爲p30pro 火爆上市");
skuMap.put("brandName", "華爲");
skuMap.put("categoryName", "手機");
skuMap.put("price", 1010221);
skuMap.put("createTime", "2019‐05‐01");
skuMap.put("saleNum", 101021);
skuMap.put("commentNum", 10102321);
Map spec = new HashMap();
spec.put("網絡制式", "移動4G");
spec.put("屏幕尺寸", "5");
skuMap.put("spec", spec);
indexRequest.source(skuMap);
bulkRequest.add(indexRequest);
//可以多次添加
// 3.獲取響應結果
try {
BulkResponse response = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
int status = response.status().getStatus();
System.out.println(status);
String message = response.buildFailureMessage();
System.out.println(message);
restHighLevelClient.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.2.2 匹配查詢
SearchRequest: 查詢請求對象
SearchResponse:查詢響應對象
SearchSourceBuilder:查詢源構建器
MatchQueryBuilder:匹配查詢構建器
這兩個類是構建查詢json對象.
查詢商品名稱包含手機的記錄
import org.apache.http.HttpHost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
public class Demo3 {
public static void main(String[] args) throws Exception{
//1.連接rest接口
HttpHost http = new HttpHost("127.0.0.1", 9200, "http");
RestClientBuilder builder = RestClient.builder(http);
RestHighLevelClient restHighLevelClient = new RestHighLevelClient(builder);
//2.封裝查詢請求
SearchRequest searchRequest = new SearchRequest("sku");
searchRequest.types("doc");//如果不寫可以查詢所有類型.
//查詢源構造器
/*
{
"query": { ---->new SearchSourceBuilder();
"match": { ---->
"name": "手機" ---->MatchQueryBuilder
}
}
}
*/
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", "手機");
searchSourceBuilder.query(matchQueryBuilder);
//相當於最外面的大括號.
searchRequest.source(searchSourceBuilder);
//3.獲取查詢結果
//相當於 _search
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHits searchHits = searchResponse.getHits();
long totalHits = searchHits.getTotalHits();
System.out.println("返回記錄數:"+totalHits);
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
String source = hit.getSourceAsString();//json字符串。也可以獲取map類型
System.out.println(source);
}
restHighLevelClient.close();
}
}
3.2.3 布爾與詞條查詢
BoolQueryBuilder:布爾查詢構建器
TermQueryBuilder:詞條查詢構建器
QueryBuilders:查詢構建器工廠
查詢名稱包含手機的,並且品牌爲小米的記錄
//1.連接rest接口 同上......
//2.封裝查詢請求
SearchRequest searchRequest=new SearchRequest("sku");
searchRequest.types("doc");
//設置查詢的類型
SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder(); BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//布爾查詢構建器
MatchQueryBuilder matchQueryBuilder= QueryBuilders.matchQuery("name","手 機");
boolQueryBuilder.must(matchQueryBuilder);
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("brandName", "小米");
boolQueryBuilder.must(termQueryBuilder);
searchSourceBuilder.query(boolQueryBuilder);
searchRequest.source(searchSourceBuilder);
//3.獲取查詢結果 同上......
3.2.4 過濾查詢
篩選品牌爲小米記錄
//1.連接rest接口 同上.....
//2.封裝查詢請求
SearchRequest searchRequest=new SearchRequest("sku");
searchRequest.types("doc");
//設置查詢的類型
SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//布爾查詢構 建器
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("brandName", "小米");
boolQueryBuilder.filter(termQueryBuilder);
searchSourceBuilder.query(boolQueryBuilder);
searchRequest.source(searchSourceBuilder);
//3.獲取查詢結果 同上....
3.2.5 分組(聚合查詢)
AggregationBuilders:聚合構建器工廠
TermsAggregationBuilder:詞條聚合構建器
Aggregations:分組結果封裝
Terms.Bucket: 桶
按商品分類分組查詢,求出每個分類的文檔數
//1.連接rest接口
HttpHost http=new HttpHost("127.0.0.1",9200,"http");
RestClientBuilder builder= RestClient.builder(http);
//rest構建器
RestHighLevelClient restHighLevelClient=new RestHighLevelClient(builder);
//高級客戶端對象
//2.封裝查詢請求
SearchRequest searchRequest=new SearchRequest("sku");
searchRequest.types("doc");
//設置查詢的類型
SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
TermsAggregationBuilder termsAggregationBuilder =
AggregationBuilders.terms("sku_category").field("categoryName");
searchSourceBuilder.aggregation(termsAggregationBuilder);
searchSourceBuilder.size(0); searchRequest.source(searchSourceBuilder);
//3.獲取查詢結果
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
Aggregations aggregations = searchResponse.getAggregations();
Map<String, Aggregation> asMap = aggregations.getAsMap();
Terms terms = (Terms) asMap.get("sku_category");
List<? extends Terms.Bucket> buckets = terms.getBuckets();
for(Terms.Bucket bucket:buckets){
System.out.println(bucket.getKeyAsString()+":"+ bucket.getDocCount());
}
restHighLevelClient.close();
把sku數據批量導入索引庫中。