日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

全文检索Elasticsearch研究

發(fā)布時(shí)間:2023/12/4 综合教程 41 生活家
生活随笔 收集整理的這篇文章主要介紹了 全文检索Elasticsearch研究 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

全文檢索Elasticsearch研究

基于虛擬機(jī)服務(wù)器自主部署ELK服務(wù)

學(xué)習(xí)目標(biāo)

  1. 了解Elasticsearch的應(yīng)用場景
  2. 學(xué)習(xí)基于服務(wù)器部署ELK服務(wù)
  3. 掌握索引維護(hù)的方法
  4. 掌握索引維護(hù)的方法
  5. 掌握基本的搜索API的使用方法

約束

需要提前掌握Lucene的索引方法、搜索方法

ELK的介紹和安裝

1.簡介

? Elasticsearch是一個(gè)基于Lucene的搜索服務(wù)器,它提供了一個(gè)分布式多用戶能力的全文搜索引擎,基于Restful web接口。Elasticsearch是用java開發(fā)的,是當(dāng)前流行的企業(yè)級搜索引擎。能到達(dá)到實(shí)時(shí)搜索,穩(wěn)定、可靠、快速、安裝使用方便。

? 我們建立一個(gè)網(wǎng)站或應(yīng)用程序,并要添加搜索功能,如果搜索的數(shù)量非常多,而且分類繁雜,如果使用傳統(tǒng)的數(shù)據(jù)庫想要完成搜索工作的創(chuàng)建失非常困難的。我們希望搜索解決方案要運(yùn)行速度快,我們希望有一個(gè)零配置和完全免費(fèi)的搜索模式,能夠簡單的使用JSON通過HTTP來索引數(shù)據(jù),而搜索服務(wù)器始終可用,并且服務(wù)器可以自如擴(kuò)展,我們一般都會使用全文檢索技術(shù),如solr、Elasticsearch等。

2.突出優(yōu)點(diǎn)

  1. 擴(kuò)展性好,可部署上百臺服務(wù)器集群,處理PB級數(shù)據(jù)
  2. 近實(shí)時(shí)的去索引數(shù)據(jù)、搜索數(shù)據(jù)

3.原理與應(yīng)用

3.1 索引結(jié)構(gòu)

下圖是ElasticSearch的索引結(jié)構(gòu),下邊==黑色部分是物理結(jié)構(gòu)==,上邊==黃色部分是邏輯結(jié)構(gòu)==,邏輯結(jié)構(gòu)可以更好的描述ElasticSearch的工作原理及去使用物理結(jié)構(gòu)中的索引文件。

BQJJij.md.png

邏輯結(jié)構(gòu)部分是一個(gè)倒排索引表:

  1. 將要搜索的文檔內(nèi)容分詞,所有不重復(fù)的詞做成分詞列表。
  2. 將搜索的文檔最終以Document方式存儲起來。
  3. 每個(gè)詞和document都有關(guān)聯(lián)。

3.2 RESTFUL應(yīng)用方法

ElasticSearch提供RESTFUL Api接口進(jìn)行索引、搜索、并且支持多種客戶端。

下圖是ElasticSearch在項(xiàng)目中的應(yīng)用方式:

BQcykR.md.png
  1. 用戶在前端搜索關(guān)鍵字
  2. 項(xiàng)目前端通過http方式請求項(xiàng)目服務(wù)端
  3. 項(xiàng)目服務(wù)端通過http RESTful方式請求ES集群進(jìn)行搜索
  4. ES集群從索引庫檢索數(shù)據(jù)

4.ElasticaSearc安裝

4.1 安裝配置

  1. 安裝ElasticaSearc7.9.0
  2. 該版本要求至少jdk1.8以上
  3. 解壓elasticsearch-7.9.0-linux-x86_64.tar.gz

    • bin:腳本目錄,包括:啟動(dòng)、停止等可執(zhí)行腳本
    • config:配置文件目錄
    • data:索引目錄,存放索引文件的地方
    • modules:模板目錄,包括了es的功能模塊
    • plugins:插件目錄,es支持插件機(jī)制

4.2 配置文件

ES配置文件的地址根據(jù)安裝形式的不同而不同:

  1. 使用zip、tar安裝,配置文件的地址在安裝目錄的config下
  2. 使用RPM安裝,配置文件在/etc/elasticsearch下
  3. 使用MSI安裝,配置文件的地址在安裝目錄的config下,并且會自動(dòng)將config目錄地址寫入環(huán)境變量ES_PATH_CONF

4.3 安裝

為了模擬真實(shí)場景,我們將在linux系統(tǒng)下安裝Elasticsearch

4.3.1 新建一個(gè)用戶gavin

處于安全考慮,Elasticsearch默認(rèn)不允許以root賬號運(yùn)行

創(chuàng)建用戶:

useradd gavin

設(shè)置密碼:

passwd gavin

切換用戶:

su gavin

刪除用戶:

userdel -r gavin

普通用戶增加sudo命令的權(quán)限:

vim /etc/sudoers

gavin   ALL=(ALL)       ALL

改變目錄及其目錄下所有文件的所有者為當(dāng)前普通用戶:

chown -R yourname dirname

4.3.3 解壓縮

tar -zxvf elasticsearch-7.9.0-linux-x86_64.tar.gz

4.3.4 目錄重命名

mv elasticsearch-7.9.0 elasticsearch

4.3.5 修改配置文件

進(jìn)入config目錄,修改elasticsearch.ymljvm.options

  1. jvm.options

默認(rèn)配置:

-Xms1g
-Xmx1g

內(nèi)存占用太多,設(shè)置為不超過物理內(nèi)存的一半:

-Xms512m
-Xmx512m
  1. elasticsearch.yml

修改數(shù)據(jù)和日志目錄

# 數(shù)據(jù)目錄位置
path.data: /home/gavin/elasticsearch/data
# 日志目錄位置
path.logs: /home/gavin/elasticsearch/logs

elasticsearch的安裝目錄默認(rèn)只有logs目錄,沒有data目錄,需要手動(dòng)創(chuàng)建:

mkdir data

修改綁定的ip:

# 綁定0.0.0.0 允許任何ip來訪問,默認(rèn)只允許本機(jī)訪問
network.host: 0.0.0.0

目前我們是學(xué)習(xí)單機(jī)安裝,如果要做集群,只需要在這個(gè)配置文件中添加節(jié)點(diǎn)信息即可。

屬性名 說明
cluster.name 配置elasticsearch的集群名稱,默認(rèn)是elasticsearch。建議修改成一個(gè)有意義的名稱。
node.name 節(jié)點(diǎn)名,es會默認(rèn)隨機(jī)指定一個(gè)名字,建議指定一個(gè)有意義的名稱,方便管理
path.conf 設(shè)置配置文件的存儲路徑,tar或zip包安裝默認(rèn)在es根目錄下的config文件夾,rpm安裝默認(rèn)在/etc/ elasticsearch
path.data 設(shè)置索引數(shù)據(jù)的存儲路徑,默認(rèn)是es根目錄下的data文件夾,可以設(shè)置多個(gè)存儲路徑,用逗號隔開
path.logs 設(shè)置日志文件的存儲路徑,默認(rèn)是es根目錄下的logs文件夾
path.plugins 設(shè)置插件的存放路徑,默認(rèn)是es根目錄下的plugins文件夾
bootstrap.memory_lock 設(shè)置為true可以鎖住ES使用的內(nèi)存,避免內(nèi)存進(jìn)行swap
network.host 設(shè)置bind_host和publish_host,設(shè)置為0.0.0.0允許外網(wǎng)訪問
http.port 設(shè)置對外服務(wù)的http端口,默認(rèn)為9200。
transport.tcp.port 集群結(jié)點(diǎn)之間通信端口
discovery.zen.ping.timeout 設(shè)置ES自動(dòng)發(fā)現(xiàn)節(jié)點(diǎn)連接超時(shí)的時(shí)間,默認(rèn)為3秒,如果網(wǎng)絡(luò)延遲高可設(shè)置大些
discovery.zen.minimum_master_nodes 主結(jié)點(diǎn)數(shù)量的最少值 ,此值的公式為:(master_eligible_nodes / 2) + 1 ,比如:有3個(gè)符合要求的主結(jié)點(diǎn),那么這里要設(shè)置為2

4.4 運(yùn)行

進(jìn)入elasticsearch/bin*目錄下,可以看到如下的可執(zhí)行文件:

然后輸入運(yùn)行命令:

./elasticsearch

4.5 啟動(dòng)報(bào)錯(cuò)

4.5.1 JDK版本過低 并且 不支持 root用戶啟動(dòng)

解決方案:

1.因?yàn)閑lasticsearch7.9.X內(nèi)置了jdk,默認(rèn)是jdk11,但是向下兼容,所以可以不用處理

2.切換到普通用戶進(jìn)行啟動(dòng),此時(shí)需要修改文件目錄下所有文件的所有者為當(dāng)前用戶。

chown?-R?gavin?/home/gavin/elasticsearch

4.5.2 集群節(jié)點(diǎn)導(dǎo)致啟動(dòng)報(bào)錯(cuò)

解決:

vim elasticsearch.yml

ip替換host1等,多節(jié)點(diǎn)請?zhí)砑佣鄠€(gè)ip地址,單節(jié)點(diǎn)可寫按默認(rèn)來
#配置以下三者,最少其一
#[discovery.seed_hosts, discovery.seed_providers, cluster.initial_master_nodes]
cluster.initial_master_nodes: ["node-1"] #這里的node-1為node-name配置的值

啟動(dòng)成功:

可以看到綁定了兩個(gè)端口:

  • 9200:客戶端訪問端口
  • 9300:集群節(jié)點(diǎn)之間通訊端口

我們在瀏覽器中訪問:http://192.168.15.100:9200/

5.安裝kibana

kibana是一個(gè)基于Node.js的Elasticsearch索引庫數(shù)據(jù)統(tǒng)計(jì)工具,可以利用Elasticsearch的聚合功能,生成各種圖表,如柱狀圖、線狀圖、餅圖等。

而且還提供了操作Elasticsearch索引數(shù)據(jù)的控制臺,并且提供了一定的API提示,非常有利于學(xué)習(xí)Elasticsearch的語法。

5.1 安裝

因?yàn)镵ibana是依賴于node

查看是否服務(wù)器是否安裝nodejs

[root@centos logs]# node -v
v9.3.0

如果沒有安裝,則安裝步驟如下:

1.可以在下載頁面https://nodejs.org/en/download/中找到下載地址,然后執(zhí)行指令

wget https://nodejs.org/dist/v9.3.0/node-v9.3.0-linux-x64.tar.xz

2.解壓縮

xz?-d?node-v9.3.0-linux-x64.tar.xz
tar?-xf?node-v9.3.0-linux-x64.tar

3.部署bin文件

根據(jù)自己nodejs的實(shí)際路徑,依次執(zhí)行下面命令,建立軟連接:

ln -s /usr/local/software/node/bin/node /usr/bin/node
ln -s /usr/local/software/node/bin/npm /usr/bin/npm
ln -s /usr/local/software/node/bin/npx /usr/bin/npx

4.測試

node -v
npm -v
npx -v

5.1.1 解壓縮kibana

tar -zxvf kibana-7.9.0-linux-x86_64.tar.gz

5.1.2 重命名安裝包

mv?kibana-7.9.0-linux-x86_64?kibana

5.1.3 修改配置

vim /home/gavin/kibana/config/kibana.yml

elasticsearch.hosts:?["http://192.168.15.100:9200"]

5.2 啟動(dòng)

cd /home/gavin/kibana/bin

./kibana

6.安裝ik分析器

Lucene的IK分詞器早在2012年就已經(jīng)沒有維護(hù)了,現(xiàn)在我們要使用的是在其基礎(chǔ)上維護(hù)升級的版本,并且開發(fā)為ElasticSearch的繼承插件了,與ElasticSearch一起維護(hù)升級了,版本也保持一致。

6.1 解壓縮

unzip?elasticsearch-analysis-ik-7.9.0.zip?-d?/home/gavin/kibana/plugins/ik-analyzer

6.2 重啟elasticsearch

加載IK分詞器插件、

6.3 測試

在Dev Tools --> console 中輸入下面請求:

POST?_analyze
{
??"analyzer":?"ik_max_word",
??"text":?????"我是中國人"
}

API

Elasticsearch提供了Rest風(fēng)格的API,即http請求接口,而且也提供了各種語言的客戶端API

文檔地址:https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html

1.客戶端API

Elasticsearch支持的客戶端非常多,如:https://www.elastic.co/guide/en/elasticsearch/client/index.html

點(diǎn)開Java Rest Client后,會有兩個(gè):

  • Java Low Level REST Client:是低級別封裝,提供一些基礎(chǔ)功能,但更靈活
  • Java High Level REST Client:是在Low Level Rest Client基礎(chǔ)上進(jìn)行的高級別封裝,功能更豐富和完善,而且API會變得簡單

2.如何學(xué)習(xí)

2.1 操作索引

Elasticsearch是基于Lucene的全文檢索庫,本質(zhì)也是存儲數(shù)據(jù),很多概念與mysql類似

對比關(guān)系:

索引(indices) --------------------------------------------- Databases 數(shù)據(jù)庫

? 類型(type) ------------------------------------------ Table 數(shù)據(jù)表

? 文檔(Document) ---------------------------Row 行

? 字段(field) -----------------------------Columns 列

說明:

概念 說明
索引庫(indices) indices是index的復(fù)數(shù),代表許多的索引
類型(type) 類型是模擬mysql中的table概念,一個(gè)索引庫下可以有不同類型的索引,比如商品索引、訂單索引,其數(shù)據(jù)格式不同。不過這會導(dǎo)致索引庫混亂,因此未來版本中會移除這個(gè)概念
文檔(document) 存入索引庫原始的數(shù)據(jù)。比如每一條商品信息,就是一個(gè)文檔
字段(field) 文檔中的屬性
映射配置(mappings) 字段的數(shù)據(jù)類型,屬性、是否索引、是否存儲等特性

特別說明:

Elasticsearch本身就是分布式的,因此即便你只有一個(gè)節(jié)點(diǎn),Elasticsearch默認(rèn)也會對你的數(shù)據(jù)進(jìn)行分片和副本操作,當(dāng)你向集群添加新數(shù)據(jù)時(shí),數(shù)據(jù)也會在新加入的節(jié)點(diǎn)中進(jìn)行平衡

2.2語法

Elasticsearch采用Rest風(fēng)格API,因此其API就是一次http請求,可以使用任何工具進(jìn)行發(fā)起http請求

2.1.1 索引庫設(shè)置
  1. 創(chuàng)建索引索引庫設(shè)置:
  • 請求方式:PUT

  • 請求路徑:/索引名

  • 請求參數(shù):json格式:

    {
    ????"settings":?{
    ????????"number_of_shards":?3,
    ????????"number_of_replicas":?2
    ??????}
    }

    settings:索引庫的設(shè)置

    number_of_shards:分片數(shù)量

    number_of_replicas:副本數(shù)量

    測試

    1. 使用postman進(jìn)行創(chuàng)建索引并對索引庫進(jìn)行設(shè)置測試

? 2. 使用kibana進(jìn)行創(chuàng)建索引并對索引庫進(jìn)行設(shè)置測試

  1. 查看索引庫設(shè)置

語法:

GET?ceshi

或者,使用*來查詢所有索引配置:

  1. 刪除索引庫設(shè)置

語法:

DELETE?/索引庫名

再次查看

2.1.2 映射配置

索引庫創(chuàng)建好之后就是添加數(shù)據(jù),再添加數(shù)據(jù)之前必須定義映射

映射:

定義文檔的過程,文檔包含哪些字段,這些字段是否保存、是否索引、是否分詞等

  1. 創(chuàng)建映射字段

    語法:

    請求方式是PUT,類型名稱和_mapping可以互換位置

    PUT?/索引庫名稱/_doc/類型名稱
    {
    ??"properties":?{
    ????"type":?"類型",
    ????"index":?true,
    ????"store":?true,
    ????"analyzer":?"分詞器"
    ??}
    }

    類型:就是前面提過的type的概念,類似于數(shù)據(jù)庫中的不同表

    字段名:任意填寫,可以指定很多屬性,如:

    • type:類型,可以是text、long、short、date、integer、object等
    • index:是否索引,默認(rèn)為true
    • store:是否存儲,默認(rèn)是false
    • analyzer:分詞器,這里的ik_max_word即表示使用ik分詞器

示例:

? 請求:

PUT?ceshi/_doc/goods
{
??"properties":?{
????"title":?{
??????"type":?"text",
??????"analyzer":?"ik_max_word"
????},
????"images":?{
??????"type":?"keyword",
??????"index":?false
????},
????"price":?{
??????"type":?"float"
????}
??}
}

特別說明:

傳統(tǒng)ES6創(chuàng)建映射的時(shí)候是把上面的**_doc換成_mapping**

ES7這個(gè)**_mapping已經(jīng)移除了,使用_doc**代替

否則會報(bào)如下錯(cuò)誤:

? 響應(yīng)結(jié)果:

{
??"_index"?:?"ceshi",
??"_type"?:?"_doc",
??"_id"?:?"goods",
??"_version"?:?3,
??"result"?:?"created",
??"_shards"?:?{
????"total"?:?2,
????"successful"?:?1,
????"failed"?:?0
??},
??"_seq_no"?:?2,
??"_primary_term"?:?1
}
  1. 查看映射關(guān)系

    語法:

    GET?索引庫名/_mapping

    示例:

    GET?ceshi/_mapping

    結(jié)果:

    1. 字段屬性詳解

3.1 type

Elasticsearch中支持的數(shù)據(jù)類型非常豐富

常用的說明下:

  • String類型,分為兩種:

    • text:可分詞,不可參與聚合
    • keyword:不可分詞,數(shù)據(jù)會作為完整字段進(jìn)行匹配,可以參與聚合
  • Numerical:數(shù)值類型,分兩類

    • 基本數(shù)據(jù)類型:long、integer、short、byte、double、float、half_float
    • 浮點(diǎn)數(shù)的高精度類型:scaled_float

      • 需要指定一個(gè)精度因子,比如10或100。Elasticsearch會把真實(shí)值乘以這個(gè)因子以后存儲,取出時(shí)再還原。
  • Date:日期類型

    • Elasticsearch可以對日期格式化為字符串存儲,但是建議我們存儲為毫秒值,存儲為long,節(jié)省空間。

3.2 index

index影響字段的索引情況

  • true:字段會被索引,則可以用來進(jìn)行搜索。默認(rèn)值是true
  • false:字段不會被索引,不能用來搜索

特別說明:

index的默認(rèn)值就是true,也就是說你不進(jìn)行任何配置,所有字段都會被索引。但是有些字段我們不希望索引的,就需要手動(dòng)設(shè)置index為false

3.3 store

是否將數(shù)據(jù)額外存儲

在lucene和solr中,我們設(shè)置store字段為false,那么這個(gè)字段在文檔列表中就不會有這個(gè)字段的值,用戶搜索結(jié)果中就不會顯示出來。

但在Elasticsearch中,即便設(shè)置為false,也可以搜索結(jié)果。

原因是Elasticsearch在創(chuàng)建文檔索引庫時(shí),會將文檔中的原始數(shù)據(jù)備份,保存到一個(gè)叫_source的屬性中,而且我們可以通過過濾_source來選擇哪些要顯示,哪些不顯示。

而如果設(shè)置storetrue,就會在_source以外額外存儲一份數(shù)據(jù),多余,因此我們一般都會講store設(shè)置為false,事實(shí)上,store的默認(rèn)是就是false

2.1.3 新增數(shù)據(jù)

1.隨機(jī)生成id

通過POST請求,可以向一個(gè)已經(jīng)存在的索引庫中添加數(shù)據(jù)

語法:

POST?/索引庫名/_doc/類型名
{
??"key":?"value"
}

示例:

POST?/ceshi/_doc/goods
{
??"title":?"小米手機(jī)",
??"images":?"http://image.leyou.com/12479122.jpg",
??"price":?2688.01
}

運(yùn)行結(jié)果:

查看新增數(shù)據(jù)結(jié)果

GET?/ceshi/_search
{
????"query":{
????????"match_all":{}
????}
}
  • _source:源文檔信息,所有數(shù)據(jù)都在里面
  • _id:這條文檔的唯一標(biāo)識,與文檔自己的id沒有關(guān)聯(lián)

2.自定義id

如果我們在新增數(shù)據(jù)的時(shí)候指定id,可以按如下操作:

語法:

POST?/索引庫名/_doc/id
{
??"key":?"value"
}

示例:

POST?/ceshi/_doc/2
{
??"title":?"小米手機(jī)",
??"images":?"http://image.leyou.com/12479122.jpg",
??"price":?2988.02
}
2.1.4 智能判斷

在學(xué)習(xí)solr時(shí),我們在新增數(shù)據(jù)時(shí),智能使用提前批配置好映射屬性的字段,否則就會報(bào)錯(cuò)

不過在Elasticsearch中,可以不需要給索引庫設(shè)置任何的映射屬性的字段,它也可以根據(jù)輸入的數(shù)據(jù)來判斷類型,動(dòng)態(tài)添加數(shù)據(jù)映射

示例:

POST?/ceshi/_doc/3
{
????"title":"超米手機(jī)",
????"images":"http://image.leyou.com/12479122.jpg",
????"price":2899.00,
????"stock":?200,
????"saleable":true
}

我們發(fā)現(xiàn),ceshi索引庫額外增加了stock庫存和saleable是否上架兩個(gè)字段。

查看此時(shí)的索引庫映射關(guān)系

GET?ceshi/_mapping
2.1.5 修改數(shù)據(jù)

把剛才新增請求的方式改為PUT,就是修改了,不過修改必須指定id

  • id對應(yīng)文檔存在,則修改
  • id對應(yīng)文檔不存在,則新增

比如,我們把id為3的數(shù)據(jù)進(jìn)行修改:

PUT?/ceshi/_doc/3
{
????"title":"超大米手機(jī)",
????"images":"http://image.leyou.com/12479122.jpg",
????"price":3899.00,
????"stock":?100,
????"saleable":true
}
2.1.6 刪除數(shù)據(jù)

刪除數(shù)據(jù)使用DELETE請求方式,同樣,根據(jù)id進(jìn)行刪除

語法:

DELETE?/索引庫名/_doc/id

示例:

DELETE?/ceshi/_doc/1

結(jié)果:刪除id為1的索引庫數(shù)據(jù)

2.1.7 查詢數(shù)據(jù)
  • 基本查詢
  • _source過濾
  • 結(jié)果過濾
  • 高級查詢
  • 排序

1.基本查詢

基本語法

GET?/索引庫名/_search
{
??"query":?{
????"查詢類型":?{
??????"查詢條件":?"查詢條件值"
????}
??}
}
  • query:表示一個(gè)查詢對象,里面可以有不同的查詢屬性

  • 查詢類型:如,mastch_allmatchtermrange

  • 查詢條件:

  • 查詢條件會根據(jù)類型的不同,寫法也有差異,后面詳細(xì)講解

2.查詢所有(match_all)

GET?/ceshi/_search
{
??"query":?{
????"match_all":?{}
??}
}
  • query:代表查詢對象
  • match_all:代表查詢所有
  • took:查詢花費(fèi)時(shí)間,單位是毫秒
  • time_out:是否超時(shí)
  • _shards:分片信息
  • hits:搜索結(jié)果總覽對象

    • total:搜索到的總條數(shù)
    • max_score:所有結(jié)果中文檔得分的最高分
    • hits:搜索結(jié)果的文檔對象數(shù)組,每個(gè)元素是一條搜索到的文檔信息

      • _index:索引庫
      • _type:文檔類型
      • _id:文檔id
      • _score:文檔得分
      • _source:文檔的源數(shù)據(jù)

3.匹配查詢(match)

先增加一條數(shù)據(jù),便于測試

PUT?/ceshi/_doc/1
{
????"title":"小米電視4A",
????"images":"http://image.leyou.com/12479122.jpg",
????"price":1899.00
}

特別說明:增加數(shù)據(jù)使用POSTPUT的區(qū)別

  • PUT:需要指定id,否則會報(bào)錯(cuò),冪等操作
  • POST:指定的id存在,則更新數(shù)據(jù),不存在要么自定義id,要么隨機(jī)生成,非冪等操作

從結(jié)果中看到,索引庫中有2部手機(jī),1臺電視

  • or關(guān)系

match類型查詢,會把查詢條件進(jìn)行分詞。然后進(jìn)行查詢,多個(gè)詞條之間是or的關(guān)系

GET?/ceshi/_search
{
??"query":?{
????"match":?{
??????"title":?"小米電視"
????}
??}
}

默認(rèn)情況下,是會通過分詞,使多個(gè)詞之間是or的關(guān)系。

  • and關(guān)系

某些時(shí)候需要精確查找,需要將多個(gè)詞關(guān)系設(shè)置為and

GET?/ceshi/_search
{
??"query":?{
????"match":?{
??????"title":?{
????????"query":?"小米電視",
????????"operator":?"and"
??????}
????}
??}
}

本例中,只有同時(shí)包含小米電視的詞條才會被搜索到

  • or and and 之間

場景:如果用戶給定的條件分詞后有5個(gè)查詢詞項(xiàng),想查找只包含其中4個(gè)詞的文檔,該如何處理?將operator操作符設(shè)置成and只會將此文檔排除。

有時(shí)候這正是我們期望的,但在全文搜索的大多數(shù)應(yīng)用場景下,我們既想包含那些可能相關(guān)的文檔,同時(shí)又排除那些不太相關(guān)的。換句話說,我們想要處于中間某種結(jié)果。

match查詢支持minimum_should_match最小匹配參數(shù),這讓我們可以指定匹配的詞項(xiàng)數(shù)用來表示一個(gè)文檔是否相關(guān)。我們可以將其設(shè)置為某個(gè)具體數(shù)字,更常用的做法是將其設(shè)置為一個(gè)百分?jǐn)?shù),因?yàn)槲覀儫o法控制用戶搜索時(shí)輸入的單詞數(shù)量。

示例:

GET?/ceshi/_search
{
??"query":?{
????"match":?{
??????"title":?{
????????"query":?"小米曲面電視",
????????"minimum_should_match":?"75%"
??????}
????}
??}
}
  • 多字段查詢(multi_match)

matchmulti_match類似,不同的是multi_match可以在多個(gè)字段中查詢

示例:

GET?/ceshi/_search
{
????"query":{
????????"multi_match":?{
????????????"query":????"小",
????????????"fields":???[?"title",?"subTitle"?]
????????}
?}
}
  • 詞條匹配(term)

term查詢被用于精確值匹配,這些精確值可能是數(shù)字、時(shí)間、布爾或者那些未分詞的字符串

示例:

GET?/ceshi/_search
{
??"query":?{
????"term":?{
?????"price":?"1899"
????}
??}
}
  • 多詞條精確匹配(terms)

terms查詢和term查詢一樣,但它允許你指定多值進(jìn)行匹配。如果這個(gè)字段中包含了指定值中的任何一個(gè)值,那么這個(gè)文檔滿足條件:

  • 結(jié)果過濾

默認(rèn)情況下,elasticsearch在搜索結(jié)果中,會把文檔中保存在_source的所有字段返回。但是,如果我們只想要獲取其中的部分字段,我們可以添加_source的過濾。

  1. 直接指定字段

    示例:

    GET?/ceshi/_search
    {
    ??"_source":?["title","price"],
    ??"query":?{
    ????"term":?{
    ??????"price":?1899
    ????}
    ??}
    }

    2. 指定includes和excludes

    我們也可以通過“

    • includes:來指定想要顯示的字段
    • excludes:來指定不想要顯示的字段

    示例:

    GET?/ceshi/_search
    {
    ??"_source":?{
    ????"includes":?["title","images"]
    ??},
    ??"query":?{
    ????"term":?{
    ??????"price":?1899
    ????}
    ??}
    }

    GET?/ceshi/_search
    {
    ??"_source":?{
    ????"excludes":?["title","images"]
    ??},
    ??"query":?{
    ????"term":?{
    ??????"price":?1899
    ????}
    ??}
    }
2.18 高級查詢

1.布爾組合(bool)

bool把各種其他查詢通過must(與)、must_not(非)、shoud(或)的當(dāng)時(shí)組合

示例

#?查詢title可能包含“大米”,但一定包含“手機(jī)”的數(shù)據(jù)
GET?/ceshi/_search
{
??"query":?{
????"bool":?{
??????"must":?{"match":{"title":"大米"}},
??????"must_not":{"match":{"title":"電視"}},
??????"should":{"match":{"title":"手機(jī)"}}
????}
??}
}

2.范圍查詢(range)

range查詢找出那些落在指定區(qū)間內(nèi)的數(shù)字或時(shí)間

示例

#?查詢price在1000-2900范圍內(nèi)的數(shù)據(jù)
GET?/ceshi/_search
{
??"query":?{
????"range":?{
??????"price":?{
????????"gte":?1000,
????????"lte":?2900
??????}
????}
??}
}

range查詢允許以下字符:

操作符 說明
gt 大于
gte 大于等于
lt 小于
lte 小于等于

3.模糊查詢(fuzzy)

新增一條數(shù)據(jù)

POST?/ceshi/_doc/4
{
????"title":"apple手機(jī)",
????"images":"http://image.leyou.com/12479122.jpg",
????"price":6899.00
}

fuzzy查詢時(shí)term查詢的模糊等價(jià)。它允許用戶搜索詞條與實(shí)際詞條的拼寫出現(xiàn)偏差,但是偏差的編輯距離不得超過2

POST?/ceshi/_doc/4
{
????"title":"apple手機(jī)",
????"images":"http://image.leyou.com/12479122.jpg",
????"price":6899.00
}

上面查詢也是可以查到apple手機(jī)數(shù)據(jù)的

我們可以通過fuzziness屬性來指定允許的偏差距離:

GET?/ceshi/_search
{
??"query":?{
????"fuzzy":?{
??????"title":?{
????????"value":?"appaa",
????????"fuzziness":?3
??????}
????}
??}
}

也是可以查到數(shù)據(jù)

注意:fuzzinexx值越大,偏差距離也越大,模糊查詢的范圍也越大,反之。

4.過濾(filter)

條件查詢找那個(gè)進(jìn)行過濾

所有的查詢都會影響到文檔的評分及排名。如果我們需要在查詢結(jié)果中進(jìn)行過濾,并且不希望過濾條件影響評分,那么就不要吧過濾條件作為查詢條件來用。而是使用filter方式:

GET?/ceshi/_search
{
??"query":?{
????"bool":?{
??????"must":{"match":{"title":"手機(jī)"}},
??????"filter":?{
????????"range":?{
??????????"price":?{
????????????"gte":?1000,
????????????"lte":?5000
??????????}
????????}
??????}
????}
??}
}

注意:filet中還可以再次進(jìn)行bool組合條件過濾

無查詢條件,直接過濾

如果一個(gè)查詢只有過濾,沒有查詢條件,不希望進(jìn)行評分,我們可以使用constant_score取代只有filter語句的bool查詢。在性能上時(shí)完全相同的,但對于提高查詢簡潔性和清晰度有很大幫助。

示例:

GET?/ceshi/_search
{
??"query":?{
????"constant_score":?{
??????"filter":?{
????????"range":?{
??????????"price":?{
????????????"gte":?1000,
????????????"lte":?4000
??????????}
????????}
??????}
????}
??}
}

5.排序

需求:想要將查詢條件title和price范圍過濾出來結(jié)果,進(jìn)行首先按照價(jià)格排序,然后按照得分排序:

GET?/ceshi/_search
{
??"query":?{
????"bool":?{
??????"must":{"match":{"title":"手機(jī)"}},
??????"filter":{
????????"range":?{
??????????"price":?{
????????????"gte":?1000,
????????????"lte":?7000
??????????}
????????}
??????}
????}
??},
??"sort":?[
????{"price":?{"order":?"desc"}},
????{"_score":?{"order":?"desc"}}
??]
}

2.3聚合aggregations

聚合可以讓我們及其方便的實(shí)現(xiàn)對數(shù)據(jù)的統(tǒng)計(jì)、分析。例如:

  • 什么品牌的手機(jī)最受歡迎
  • 這些手機(jī)的平均價(jià)格、最高價(jià)格、最低價(jià)格
  • 這些手機(jī)每月的銷售情況如何

實(shí)現(xiàn)這些統(tǒng)計(jì)功能要比數(shù)據(jù)庫的sql方便的多,而且查詢速度非常快,可以實(shí)現(xiàn)實(shí)時(shí)搜索效果。

2.3.1 基本概念

Elasticsearch中的聚合,包含多種類型,最常用的兩種:

  • 度量
1.桶(bucket)

桶的作用,是按照某種方式對數(shù)據(jù)進(jìn)行分組,每一組數(shù)據(jù)在ES中稱為一個(gè)桶。例如,我們根據(jù)國籍對人劃分,可以得到中國桶、英國桶、美國桶。。。

Elasticsearch中提供的劃分桶的方式很多:

  • Date Histogram Aggregation:根據(jù)日期階梯分組,例如給定階梯為周,會自動(dòng)每周分一組
  • Histogram Aggregation:根據(jù)數(shù)值階梯分組,與日期類似
  • Terms Aggregation:根據(jù)詞條內(nèi)容分組,詞條內(nèi)容完全匹配分為一組
  • Range Aggregation:數(shù)值和日期的范圍分組,指定開始和結(jié)束,然后分段分組
  • 。。。

綜上所述,我們發(fā)現(xiàn)bucket aggregations只負(fù)責(zé)對數(shù)據(jù)進(jìn)行分組,并不進(jìn)行計(jì)算,因此bucket中往往會嵌套另一種聚合:metrics aggregations 即度量

2.度量(metrics)

分組完成以后,我們一般會對組中的數(shù)據(jù)進(jìn)行聚合運(yùn)算,例如求平均值、最大、最小、求和等操作。這些在ES中稱為度量

比較常用的一些度量聚合方式:

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

開始測試

為了方便測試,我們首先批量導(dǎo)入測試數(shù)據(jù)

2.3.2 創(chuàng)建索引庫
PUT?/cars
{
??"settings":?{
????"number_of_shards":?1,
????"number_of_replicas":?0
??},
??"mappings":?{
??????"properties":{
????????"color":{"type":"keyword"},
????????"make":{"type":"keyword"}
????}
??}
}

查看索引庫映射關(guān)系:GET /cars/_mapping

注意:在ES中,需要進(jìn)行聚合、排序、過濾的字段其處理方式比較特殊,因此不能被分詞。這里我們將color和make這兩個(gè)字段類型設(shè)置為keyword類型,這個(gè)類型不會被分詞,將來就可以參與聚合

導(dǎo)入數(shù)據(jù):

POST?/cars/_bulk
{?"index":?{}}
{?"price"?:?10000,?"color"?:?"red",?"make"?:?"honda",?"sold"?:?"2014-10-28"?}
{?"index":?{}}
{?"price"?:?20000,?"color"?:?"red",?"make"?:?"honda",?"sold"?:?"2014-11-05"?}
{?"index":?{}}
{?"price"?:?30000,?"color"?:?"green",?"make"?:?"ford",?"sold"?:?"2014-05-18"?}
{?"index":?{}}
{?"price"?:?15000,?"color"?:?"blue",?"make"?:?"toyota",?"sold"?:?"2014-07-02"?}
{?"index":?{}}
{?"price"?:?12000,?"color"?:?"green",?"make"?:?"toyota",?"sold"?:?"2014-08-19"?}
{?"index":?{}}
{?"price"?:?20000,?"color"?:?"red",?"make"?:?"honda",?"sold"?:?"2014-11-05"?}
{?"index":?{}}
{?"price"?:?80000,?"color"?:?"red",?"make"?:?"bmw",?"sold"?:?"2014-01-01"?}
{?"index":?{}}
{?"price"?:?25000,?"color"?:?"blue",?"make"?:?"ford",?"sold"?:?"2014-02-12"?}

查看cars索引庫中的數(shù)據(jù):

GET?/cars/_search
{
??"query":?{
????"match_all":?{}
??}
}
2.3.3 聚合為桶
1.按照cars中的color字段來劃分桶
GET?/cars/_search
{
????"size"?:?0,
????"aggs"?:?{?
????????"popular_colors"?:?{?
????????????"terms"?:?{?
??????????????"field"?:?"color"
????????????}
????????}
????}
}
  • size:查詢條數(shù),這里設(shè)置為0,因?yàn)槲覀儾魂P(guān)心搜索到的數(shù)據(jù),只關(guān)心聚合結(jié)果,提高效率
  • aggs:聲明這是一個(gè)聚合查詢,是aggregations的縮寫

    • popular_color:給這次聚合起一個(gè)名字,任意。

      • terms:劃分桶的方式,這里是根據(jù)詞條劃分

        • field:劃分桶的字段
  • hits:查詢結(jié)果為空,因?yàn)槲覀冊O(shè)置了size為0
  • aggregations:聚合的結(jié)果

    • popular_clor:我們定義的聚合名稱

      • buckets:查找到的桶,每個(gè)不同的color字段值都會形成一個(gè)桶

        • key:這個(gè)桶對應(yīng)的color字段的值
        • doc_count:這個(gè)桶中的文檔數(shù)量

總結(jié):通過聚合的結(jié)果我們發(fā)現(xiàn),目前紅色的小車比較暢銷

2.3.4 桶內(nèi)度量

前面的例子告訴我們每個(gè)桶里面的文檔數(shù)量。但通常,我們的應(yīng)用需要提供更為復(fù)雜的文檔度量。例如,每種顏色騎車的平均價(jià)格是多少?

因此,我們需要告訴Elasticsearch使用哪個(gè)字段,使用何種度量方式進(jìn)行運(yùn)算,這些信息要嵌套在==桶內(nèi)==,度量的運(yùn)算會基于==桶內(nèi)==的文檔進(jìn)行。

示例:

需求:按照cars中的color字段劃分桶,并求相應(yīng)每個(gè)桶中的平均價(jià)格

GET?/cars/_search
{
??"size":?0,
??"aggs":?{
????"popular_color":?{
??????"terms":?{
????????"field":?"color"
??????},
??????"aggs":?{
????????"avg_price":?{
??????????"avg":?{
????????????"field":?"price"
??????????}
????????}
??????}
????}
??}
}
  • arrgs:我們在aggs(popular_color)中添加新的aggs。可見==度量也是一個(gè)聚合,度量是在桶中的聚合==。
  • avg_price:度量聚合的名稱,任意
  • avg:度量的類型,這里是求平均值
  • field:度量運(yùn)算的字段

結(jié)果:

我們可以看到每個(gè)桶中都有自己的avg_price字段,這就是度量聚合的結(jié)果

2.3.5 桶內(nèi)嵌套桶

上面示例是桶內(nèi)嵌套度量運(yùn)算。事實(shí)上桶內(nèi)不僅可以嵌套運(yùn)算,還可以嵌套其他桶。也就是說在每個(gè)分組中,可以再分更多桶。

示例:

需求:我們想要統(tǒng)計(jì)每種顏色的汽車中,分別屬于哪個(gè)制造商,按照make字段在進(jìn)行分桶

GET?/cars/_search
{
??"size":?0,
??"aggs":?{
????"popular_color":?{
??????"terms":?{
????????"field":?"color"
??????},
??????"aggs":?{
????????"avg_price":?{
??????????"avg":?{
????????????"field":?"price"
??????????}
????????},
????????"maker":{
??????????"terms":?{
????????????"field":?"make"
??????????}
????????}
??????}
????}
??}
}

結(jié)果:

{
??"took"?:?14,
??"timed_out"?:?false,
??"_shards"?:?{
????"total"?:?1,
????"successful"?:?1,
????"skipped"?:?0,
????"failed"?:?0
??},
??"hits"?:?{
????"total"?:?{
??????"value"?:?8,
??????"relation"?:?"eq"
????},
????"max_score"?:?null,
????"hits"?:?[?]
??},
??"aggregations"?:?{
????"popular_color"?:?{
??????"doc_count_error_upper_bound"?:?0,
??????"sum_other_doc_count"?:?0,
??????"buckets"?:?[
????????{
??????????"key"?:?"red",
??????????"doc_count"?:?4,
??????????"maker"?:?{
????????????"doc_count_error_upper_bound"?:?0,
????????????"sum_other_doc_count"?:?0,
????????????"buckets"?:?[
??????????????{
????????????????"key"?:?"honda",
????????????????"doc_count"?:?3
??????????????},
??????????????{
????????????????"key"?:?"bmw",
????????????????"doc_count"?:?1
??????????????}
????????????]
??????????},
??????????"avg_price"?:?{
????????????"value"?:?32500.0
??????????}
????????},
????????{
??????????"key"?:?"blue",
??????????"doc_count"?:?2,
??????????"maker"?:?{
????????????"doc_count_error_upper_bound"?:?0,
????????????"sum_other_doc_count"?:?0,
????????????"buckets"?:?[
??????????????{
????????????????"key"?:?"ford",
????????????????"doc_count"?:?1
??????????????},
??????????????{
????????????????"key"?:?"toyota",
????????????????"doc_count"?:?1
??????????????}
????????????]
??????????},
??????????"avg_price"?:?{
????????????"value"?:?20000.0
??????????}
????????},
????????{
??????????"key"?:?"green",
??????????"doc_count"?:?2,
??????????"maker"?:?{
????????????"doc_count_error_upper_bound"?:?0,
????????????"sum_other_doc_count"?:?0,
????????????"buckets"?:?[
??????????????{
????????????????"key"?:?"ford",
????????????????"doc_count"?:?1
??????????????},
??????????????{
????????????????"key"?:?"toyota",
????????????????"doc_count"?:?1
??????????????}
????????????]
??????????},
??????????"avg_price"?:?{
????????????"value"?:?21000.0
??????????}
????????}
??????]
????}
??}
}
  • 我們可以看到,新的聚合maker被嵌套在原來每一個(gè)color的桶中。
  • 每個(gè)顏色下面都根據(jù)make字段進(jìn)行了分組
  • 我們從結(jié)果中讀到的信息:

    • 紅色車共有4輛
    • 紅色車的平均售價(jià)32500
    • 其中3輛是Honda本田制造,1輛是BMW寶馬制造
2.3.6 階梯分桶(Histogram)

histogram是把數(shù)值類型的字段,按照一定的階梯大小進(jìn)行分組。需要指定一個(gè)階梯值(interval)來劃分階梯大小

示例

需求:比如你有價(jià)格字段,如果你設(shè)定interval的值為200.那么階梯就會是這樣的:

0,200,400,600,。。。

上面列出的是每個(gè)階梯的key,也是區(qū)間的起點(diǎn)

如果一件商品的價(jià)格是450,會落在哪個(gè)階梯區(qū)間呢?計(jì)算公式如下:

bucket_key = Math.floor((value-offset)/interval)*interval+offset

  • value:就是當(dāng)前數(shù)據(jù)的值,本例中是450
  • offset:起始偏移值,默認(rèn)為0
  • interval:階梯間隔,比如200

總結(jié)

以上是生活随笔為你收集整理的全文检索Elasticsearch研究的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。