ElasticSearch
- 官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/getting-started.html
- 非官方中文文檔:https://learnku.com/docs/elasticsearch73/7.3
- 極簡(jiǎn)概括:基于Apache Lucene構(gòu)建開源的分布式搜索引擎蘸拔。
- 解決問題:MySQL like中文全文搜索不走索引师郑,或大數(shù)據(jù)搜索性能低下的問題。
- 適用場(chǎng)景:
- 大數(shù)據(jù)檢索:在大數(shù)據(jù)量的查詢場(chǎng)景下调窍,ES查詢性能依然保持優(yōu)勢(shì)宝冕,常用于替代MySQL由于性能不足而做一些復(fù)雜的查詢。
- 大數(shù)據(jù)開發(fā):大數(shù)據(jù)開發(fā)幾乎離不開Spark邓萨、Fink地梨、Hadoop、ElasticSearch缔恳、MySQL宝剖、Redis、ZooKeeper這些組件歉甚。
- ELK結(jié)合:ES結(jié)合LK作為ELK(Elasticsearch(搜索), Logstash(采集轉(zhuǎn)換), Kibana(分析))組合万细,可用于實(shí)時(shí)監(jiān)控、分析和可視化大量日志和事件數(shù)據(jù)铃芦,如系統(tǒng)日志雅镊、應(yīng)用程序日志襟雷、網(wǎng)絡(luò)流量日志等。
- 優(yōu)點(diǎn):
- 跨平臺(tái):組件支持在Linux仁烹、Windows耸弄、MacOS上運(yùn)行。
- 查詢性能優(yōu)異:在超大數(shù)據(jù)量的查詢場(chǎng)景下卓缰,ES查詢性能依然保持優(yōu)勢(shì)计呈。
- 支持全文檢索:替代MySQL中文全文檢索不走索引的查詢?nèi)蹴?xiàng)。
- 生態(tài)繁榮:是面向開發(fā)者的主流的搜索引擎征唬,文檔捌显,解決方案,疑難雜癥总寒,非0day漏洞扶歪,基本都有成熟的解決方案。
- 支持分布式:每個(gè)ES節(jié)點(diǎn)摄闸,都可以執(zhí)行一部分搜索任務(wù)善镰,然后將結(jié)果合并。累加的算力效果如虎添翼年枕。
- 支持復(fù)雜查詢:支持炫欺,模糊匹配,范圍查詢熏兄,布爾搜索品洛。
- 缺點(diǎn):
- ES沒有事務(wù)機(jī)制,對(duì)于MySQL的合作呢摩桶,也是最終一致性桥状,所以強(qiáng)一致性的搜索環(huán)境下并不適用,推薦Redis典格。
- json請(qǐng)求體父子格式反人類:果然技術(shù)厲害的程序員往往不會(huì)是一個(gè)好的產(chǎn)品經(jīng)理岛宦。
- json響應(yīng)體格式反人類,按照["成功或失敗的code", "data數(shù)據(jù)", "msg補(bǔ)充說明"]這種格式返回就好了耍缴。
- PHP API經(jīng)常性異常:APi接口砾肺,寫操作失敗返回false也行,非要返回異常防嗡,異常若沒有處理变汪,會(huì)中斷程序執(zhí)行。
- 查詢方式受mapping限制:相比于MySQL蚁趁,哪怕是個(gè)數(shù)字裙盾,都可以用like強(qiáng)制查詢,但是ES不行。
- 同類組件:Apache Solr番官、Apache Lucene庐完、Algolia、Sphinx徘熔、XunSearch门躯。
正排索引和倒排索引
ES用的倒排索引算法。正倒兩種索引都是用于快速檢索數(shù)據(jù)的實(shí)現(xiàn)方案酷师,我沒有太官方的解釋讶凉,所以舉例說明:
- 正排索引:有一個(gè)文章表,有文章id山孔、標(biāo)題宅楞、詳情3個(gè)字段草戈,通過文章列表功能獲取文章旗国,通過id作為索引值獲取文章內(nèi)容裸影,這是很普遍的業(yè)務(wù)邏輯。想要搜索包含指定關(guān)鍵詞的文章蓉媳,數(shù)據(jù)庫就需要對(duì)文章的標(biāo)題和內(nèi)容逐一做對(duì)比譬挚,因?yàn)椴蛔咚饕瑪?shù)據(jù)量不大還好酪呻,數(shù)據(jù)量一大性能降低。
- 倒排索引:用于加速文本的檢索盐须,文章內(nèi)容利用分詞器拆分玩荠,將拆分好的關(guān)鍵詞與文章id做關(guān)聯(lián),然后保存贼邓。類比MySQL表的兩個(gè)列阶冈,一列是關(guān)鍵詞,另一列是包含這個(gè)關(guān)鍵詞的文章id塑径,多個(gè)倒排索引數(shù)據(jù)集組成一個(gè)倒排表女坑。再查詢時(shí),不需要針對(duì)數(shù)據(jù)源本身做查詢统舀,而是變成了匆骗,關(guān)鍵詞為xxx的id為多少。
分詞
分詞就是把字符串拆分成有用的關(guān)鍵詞誉简,用于提供高質(zhì)量搜索的數(shù)據(jù)源碉就。
- 對(duì)英文:分詞直接用空格就行,I love you闷串,可直接利用空格分成3個(gè)詞瓮钥,對(duì)中文顯然不適用。
- 對(duì)中文:例如“今天溫度很高”,能用的詞匯可以拆分成“今天”碉熄、“溫度”桨武、“很高”,可程序不知道怎么拆分锈津,若拆分為“今天溫”玻募、“天溫”、“”度很”這樣的關(guān)鍵詞就顯得很怪異一姿。
所以也就誕生了語法分析+字典的解決方案七咧,用人工干涉+詞典的方式實(shí)現(xiàn)分詞器的邏輯。
至于利用NLP語義分析叮叹,上下文預(yù)測(cè)艾栋,的AI模式,不屬于ES的范疇蛉顽,不展開蝗砾。 - 若搜索關(guān)鍵詞為語句或短語:需要利用TF-IDF和BM25算法(等更高級(jí)的算法),先對(duì)句子進(jìn)行分詞携冤,然后根據(jù)這多個(gè)分詞的再對(duì)結(jié)果集進(jìn)行分詞查詢悼粮,然后評(píng)分,組合曾棕,最終返回結(jié)果扣猫。
安裝ES 8.14.1
- 系統(tǒng)配置,用于開啟防火墻翘地,創(chuàng)建用戶申尤,和大數(shù)據(jù)情況下提升性能。
Java寫的組件吃內(nèi)存衙耕,建議VM虛擬機(jī)內(nèi)存設(shè)置大一點(diǎn)昧穿,系統(tǒng)設(shè)置為1G內(nèi)存。
開兩個(gè)端口橙喘,并重啟防火墻
firewall-cmd --add-port=9200/tcp --zone=public --permanent
firewall-cmd --add-port=9300/tcp --zone=public --permanent
systemctl restart firewalld
新建一個(gè)es用戶时鸵,以非root形式運(yùn)行,否則運(yùn)行es會(huì)報(bào)錯(cuò)厅瞎,java.lang.RuntimeException: can not run elasticsearch as root
useradd -M es
passwd es 密碼為123456
vim /etc/security/limits.conf
文末添加兩行配置饰潜,優(yōu)化文件描述符軟硬限制,對(duì)提高性能非常重要磁奖,文件描述符用于標(biāo)識(shí)和管理每個(gè)進(jìn)程都可以打開文件的數(shù)量
es soft nofile 65536
es hard nofile 65536
vim /etc/security/limits.d/20-nproc.conf
文末添加兩行配置囊拜,優(yōu)化文件描述符軟硬限制,對(duì)提高性能非常重要比搭,文件描述符用于標(biāo)識(shí)和管理每個(gè)進(jìn)程都可以打開文件的數(shù)量
es soft nofile 65536
es hard nofile 65536
vim /etc/sysctl.conf
定義系統(tǒng)中可以同時(shí)打開的最大文件描述符數(shù)量冠跷。
fs.file-max=655350
定義Linux內(nèi)核中進(jìn)程可以擁有的最大內(nèi)存映射區(qū)域數(shù)量
vm.max_map_count=262144
重啟
sysctl -p
- 安裝相關(guān)
下載tar包并解壓南誊,這個(gè)包地址來源于官網(wǎng),并非java源碼包
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.14.1-linux-x86_64.tar.gz
tar zxf elasticsearch-8.14.1-linux-x86_64.tar.gz
更改所屬的用戶和用戶組
chown -R es:es elasticsearch-8.14.1
切換用戶
su es
啟動(dòng)ES蜜托,如果發(fā)現(xiàn)報(bào)錯(cuò)抄囚,請(qǐng)清空bin目錄同級(jí)的data目錄
./bin/elasticsearch
啟動(dòng)后,直到看到如下字樣橄务,說明能成功啟動(dòng)幔托,但是輸入它生成的用戶名密碼,登不進(jìn)去
然后Ctrl + C強(qiáng)制停止蜂挪,因?yàn)閱?dòng)一次之后重挑,config/elasticsearch.yml配置文件,會(huì)發(fā)生變化棠涮,這一步不可少
Elasticsearch security features have been automatically configured!
登不進(jìn)去谬哀,那就改配置
vim config/elasticsearch.yml
把91~103行的true全部改為false,如下严肪,注意配置格式史煎,key: value之間要留出空格,否則ES不識(shí)別對(duì)應(yīng)的值驳糯。
# Enable security features
xpack.security.enabled: false
xpack.security.enrollment.enabled: false
# Enable encryption for HTTP API client connections, such as Kibana, Logstash, and Agents
xpack.security.http.ssl:
enabled: false
keystore.path: certs/http.p12
# Enable encryption and mutual authentication between cluster nodes
xpack.security.transport.ssl:
enabled: false
保存退出后篇梭,清除初始化的data數(shù)據(jù)
rm -rf elasticsearch-8.14.1/data/*
再次執(zhí)行,并使其后臺(tái)運(yùn)行
./bin/elasticsearch -d
查看進(jìn)程酝枢,確定ES是否成功執(zhí)行
ps aux | grep elastic
es 49044 30.2 64.3 8291804 640416 pts/0 Sl 05:08 0:26 /test/elasticsearch-8.14.1/jdk/bin/java -Des.networkaddress.cache.ttl=60 -Des.networkaddress.cache.negative.ttl=10 -Djava.security.manager=allow -XX:+AlwaysPreTouch -Xss1m -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djna.nosys=true -XX:-OmitStackTraceInFastThrow -Dio.netty.noUnsafe=true -Dio.netty.noKeySetOptimization=true -Dio.netty.recycler.maxCapacityPerThread=0 -Dlog4j.shutdownHookEnabled=false -Dlog4j2.disable.jmx=true -Dlog4j2.formatMsgNoLookups=true -Djava.locale.providers=SPI,COMPAT --add-opens=java.base/java.io=org.elasticsearch.preallocate --add-opens=org.apache.lucene.core/org.apache.lucene.store=org.elasticsearch.vec --enable-native-access=org.elasticsearch.nativeaccess -XX:ReplayDataFile=logs/replay_pid%p.log -Djava.library.path=/test/elasticsearch-8.14.1/lib/platform/linux-x64:/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib -Djna.library.path=/test/elasticsearch-8.14.1/lib/platform/linux-x64:/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib -Des.distribution.type=tar -XX:+UnlockDiagnosticVMOptions -XX:G1NumCollectionsKeepPinned=10000000 -XX:+UseG1GC -Djava.io.tmpdir=/tmp/elasticsearch-13971958964404181235 --add-modules=jdk.incubator.vector -XX:+HeapDumpOnOutOfMemoryError -XX:+ExitOnOutOfMemoryError -XX:HeapDumpPath=data -XX:ErrorFile=logs/hs_err_pid%p.log -Xlog:gc*,gc+age=trace,safepoint:file=logs/gc.log:utctime,level,pid,tags:filecount=32,filesize=64m -Xms389m -Xmx389m -XX:MaxDirectMemorySize=204472320 -XX:G1HeapRegionSize=4m -XX:InitiatingHeapOccupancyPercent=30 -XX:G1ReservePercent=15 --module-path /test/elasticsearch-8.14.1/lib --add-modules=jdk.net --add-modules=ALL-MODULE-PATH -m org.elasticsearch.server/org.elasticsearch.bootstrap.Elasticsearch
es 49075 0.0 0.0 55180 880 pts/0 Sl 05:09 0:00 /test/elasticsearch-8.14.1/modules/x-pack-ml/platform/linux-x86_64/bin/controller
es 49230 0.0 0.0 112828 968 pts/0 R+ 05:10 0:00 grep elastic
訪問:
http://IP:9200/
設(shè)置密碼(推薦添加)
上文配置的是沒有密碼的方案恬偷,倘若服務(wù)器IP和端口對(duì)外暴露,這不是一種安全的行為隧枫。
注意喉磁,要部署集群,各個(gè)節(jié)點(diǎn)密碼應(yīng)當(dāng)一致官脓。
注意配置格式,key: value之間要留出空格涝焙,否則ES不識(shí)別對(duì)應(yīng)的值卑笨。
vim es根目錄/config/elasticsearch.yml
修改以下配置
xpack.security.enabled: true
非root用戶下啟動(dòng)es
./bin/elasticsearch -d
啟動(dòng)一個(gè)交互式命令行界面,從而設(shè)置密碼仑撞,期間的幾個(gè)交互赤兴,全部設(shè)置為123456
./bin/elasticsearch-setup-passwords interactive
默認(rèn)用戶名:elastic
密碼:123456
概念輔助類比
ES中有些新的概念,可通過MySQL的概念去輔助記憶隧哮。
ES | MySQL | 備注 |
---|---|---|
Index(索引) | 庫表 | / |
Type(類型) | 表 | 7及以上的版本被移除桶良,原先是對(duì)標(biāo)MySQL表的理念,后來發(fā)現(xiàn)這對(duì)于ES并非必須沮翔,就移除了 |
Documents(文檔) | 行數(shù)據(jù) | / |
Fields(字段) | 字段 | / |
Mapping(映射) | 表結(jié)構(gòu) | / |
Shards(分片) | 分表 | 顧名思義陨帆,當(dāng)數(shù)據(jù)量太大單個(gè)節(jié)點(diǎn)都裝不下的時(shí)候,就拆分到其它節(jié)點(diǎn)上 |
默認(rèn)頁說明
- 默認(rèn)頁:
GET請(qǐng)求IP:9200/
{
"name": "lnmp",
"cluster_name": "elasticsearch",
"cluster_uuid": "k61PBMDqTKO31rZeV-ENGA",
"version": {
"number": "8.14.1",
"build_flavor": "default",
"build_type": "tar",
"build_hash": "93a57a1a76f556d8aee6a90d1a95b06187501310",
"build_date": "2024-06-10T23:35:17.114581191Z",
"build_snapshot": false,
"lucene_version": "9.10.0",
"minimum_wire_compatibility_version": "7.17.0",
"minimum_index_compatibility_version": "7.0.0"
},
"tagline": "You Know, for Search"
}
"name": "lnmp":系統(tǒng)標(biāo)識(shí)
"cluster_name": "elasticsearch":Elasticsearch 集群的名稱為 “elasticsearch”。
"cluster_uuid": "k61PBMDqTKO31rZeV-ENGA":Elasticsearch集群的唯一標(biāo)識(shí)符疲牵。
"version":版本信息:
"number": 版本號(hào)
"build_flavor": "default":構(gòu)建的類型承二,這里是默認(rèn)的。
"build_type": "tar":構(gòu)建類型為 tar 包纲爸。
"build_hash": "93a57a1a76f556d8aee6a90d1a95b06187501310":構(gòu)建的哈希值亥鸠,用于唯一標(biāo)識(shí)這個(gè)特定的構(gòu)建。
"build_date": "2024-06-10T23:35:17.114581191Z":構(gòu)建的日期和時(shí)間识啦。
"build_snapshot": false:表示這個(gè)構(gòu)建不是一個(gè)快照版本负蚊。
"lucene_version": "9.10.0":基于Lucene 9.10.0的版本。
"minimum_wire_compatibility_version": "7.17.0":最低兼容的網(wǎng)絡(luò)傳輸版本颓哮。
"minimum_index_compatibility_version": "7.0.0":最低兼容的索引版本家妆。
"tagline": "You Know, for Search":Elasticsearch 的標(biāo)語,說明其用途是進(jìn)行搜索题翻。
索引增刪查操作
- 創(chuàng)建索引:
PUT請(qǐng)求 IP:9200/索引名
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "zs_index"
}
"acknowledged": true:指示請(qǐng)求是否被成功接受和處理揩徊。
"shards_acknowledged": true:指示所有分片是否已經(jīng)確認(rèn)請(qǐng)求。
"index": "zs_index":這表示操作涉及的索引名稱為 “zs_index”嵌赠。
- 創(chuàng)建索引:
重復(fù)創(chuàng)建塑荒,報(bào)錯(cuò)說明:
{
"error": {
"root_cause": [
{
"type": "resource_already_exists_exception",
"reason": "index [zs_index/dCMAgdlqTeaihB4JSH1gNw] already exists",
"index_uuid": "dCMAgdlqTeaihB4JSH1gNw",
"index": "zs_index"
}
],
"type": "resource_already_exists_exception",
"reason": "index [zs_index/dCMAgdlqTeaihB4JSH1gNw] already exists",
"index_uuid": "dCMAgdlqTeaihB4JSH1gNw",
"index": "zs_index"
},
"status": 400
}
"error":這個(gè)對(duì)象包含了發(fā)生的錯(cuò)誤信息。
"root_cause":根本原因的數(shù)組姜挺,指示導(dǎo)致問題的具體原因齿税。
"type": "resource_already_exists_exception":錯(cuò)誤的類型,表示嘗試創(chuàng)建的索引已經(jīng)存在炊豪。
"reason": "index [zs_index/dCMAgdlqTeaihB4JSH1gNw] already exists":錯(cuò)誤的詳細(xì)原因凌箕,指明索引 “zs_index” 和其唯一標(biāo)識(shí)符 “dCMAgdlqTeaihB4JSH1gNw” 已經(jīng)存在。
"index_uuid": "dCMAgdlqTeaihB4JSH1gNw":已存在索引的 UUID词渤。
"index": "zs_index":已存在索引的名稱牵舱。
"type": "resource_already_exists_exception":總體錯(cuò)誤類型,與根本原因相同缺虐。
"reason": "index [zs_index/dCMAgdlqTeaihB4JSH1gNw] already exists":再次指明索引已經(jīng)存在的原因芜壁。
"index_uuid": "dCMAgdlqTeaihB4JSH1gNw":重復(fù)指定已存在索引的 UUID。
"index": "zs_index":重復(fù)指定已存在索引的名稱高氮。
"status": 400:HTTP 狀態(tài)碼慧妄,表示客戶端請(qǐng)求錯(cuò)誤
- 查看索引:
GET請(qǐng)求 IP:9200/索引名
{
"zs_index": {
"aliases": {},
"mappings": {},
"settings": {
"index": {
"routing": {
"allocation": {
"include": {
"_tier_preference": "data_content"
}
}
},
"number_of_shards": "1",
"provided_name": "zs_index",
"creation_date": "1719699272706",
"number_of_replicas": "1",
"uuid": "dCMAgdlqTeaihB4JSH1gNw",
"version": {
"created": "8505000"
}
}
}
}
}
"aliases": {}:索引的別名列表為空,表示該索引當(dāng)前沒有別名剪芍。
"mappings": {}:索引的映射為空對(duì)象塞淹,即沒有定義特定的字段映射。
"settings":索引的設(shè)置信息:
"index":
"routing":
"allocation":
"include":
"_tier_preference": "data_content":指定索引分配時(shí)偏好的數(shù)據(jù)內(nèi)容層級(jí)罪裹。
"number_of_shards": "1":該索引被分成了一個(gè)分片饱普。
"provided_name": "zs_index":索引的提供的名稱為 “zs_index”运挫。
"creation_date": "1719699272706":索引的創(chuàng)建日期的時(shí)間戳形式。
"number_of_replicas": "1":該索引有一個(gè)副本费彼。
"uuid": "dCMAgdlqTeaihB4JSH1gNw":索引的唯一標(biāo)識(shí)符 UUID滑臊。
"version":
"created": "8505000":索引的版本信息,表示索引在 Elasticsearch 版本 “8505000” 中創(chuàng)建箍铲。
- 查看所有索引:
GET請(qǐng)求 IP:9200/_cat/indices?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size dataset.size
yellow open zs_index dCMAgdlqTeaihB4JSH1gNw 1 1 0 0 249b 249b 249b
health: 索引的健康狀態(tài)雇卷,此處為 “yellow”,表示所有預(yù)期的分片都可用颠猴,但副本尚未分配关划。
status: Elasticsearch 的狀態(tài)指示符,這里是 “open”翘瓮,表示索引是打開狀態(tài)贮折,可以接收讀寫操作。
index: 索引名资盅。
uuid: 索引的唯一標(biāo)識(shí)符调榄。
pri: 主分片數(shù)為 1,即索引被分成了一個(gè)主分片呵扛。
rep: 副本數(shù)為 1每庆,表示每個(gè)主分片有一個(gè)副本。
docs.count: 文檔數(shù)量為 0今穿,當(dāng)前索引中的文檔總數(shù)缤灵。
docs.deleted: 已刪除的文檔數(shù)量為 0。
store.size: 存儲(chǔ)大小為 249b蓝晒,索引占用的物理存儲(chǔ)空間腮出。
pri.store.size: 主分片的存儲(chǔ)大小,也是 249b芝薇。
dataset.size: 數(shù)據(jù)集大小為 249b胚嘲,即索引的數(shù)據(jù)集大小。
- 刪除索引 DELETE方式 IP:9200/索引名
{
"acknowledged": true
}
返回true表示成功執(zhí)行洛二。
文檔增刪改查操作
- 增文檔(數(shù)據(jù)):
方式1:POST請(qǐng)求 IP:9200/索引名/_doc/可選參數(shù)慢逾,數(shù)據(jù)唯一標(biāo)識(shí)
方式2:PUT請(qǐng)求 IP:9200/索引名/_create/必填唯一標(biāo)識(shí)符 由于方式2的put請(qǐng)求是冪等,所以再次請(qǐng)求會(huì)報(bào)錯(cuò)
這是存入的數(shù)據(jù)
{
"id":1,
"content":"C是世界上最好的編程語言"
}
這是返回的數(shù)據(jù)灭红,若用戶指定id,則id處顯示的是用戶指定的id
{
"_index": "zs_index",
"_id": "0mMsZpABZdTHCHXLZQhu",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
"_index": "zs_index": 表示文檔被添加到了名為zs_index的索引中口注。
"_id": "0mMsZpABZdTHCHXLZQhu": 是新添加的文檔的ID变擒。在Elasticsearch中,每個(gè)文檔都有一個(gè)唯一的ID寝志,用于唯一標(biāo)識(shí)和檢索該文檔娇斑。
"_version": 1: 表示該文檔的版本號(hào)是1策添。每當(dāng)文檔被更新時(shí),版本號(hào)會(huì)增加毫缆,這有助于跟蹤文檔的更改歷史唯竹。
"result": "created": 表示操作的結(jié)果是創(chuàng)建了一個(gè)新的文檔。
"_shards": 這個(gè)字段提供了關(guān)于索引操作的分片信息苦丁。
"total": 2: 表示總共有2個(gè)分片參與了這次索引操作(通常是一個(gè)主分片和其副本)浸颓。
"successful": 1: 表示有1個(gè)分片成功完成了索引操作。在yellow健康狀態(tài)的索引中旺拉,這通常意味著主分片成功了产上,但副本分片可能還沒有數(shù)據(jù)(因?yàn)樗莥ellow狀態(tài),副本可能還沒有分配或同步)蛾狗。
"failed": 0: 表示沒有分片失敗晋涣。
"_seq_no": 0: 是文檔在Lucene段中的序列號(hào),用于在內(nèi)部跟蹤文檔的版本和順序沉桌。
"_primary_term": 1: 主要術(shù)語(primary term)是與_seq_no一起使用的谢鹊,用于確保文檔版本的一致性,特別是在主節(jié)點(diǎn)更換時(shí)留凭。
- 改文檔(數(shù)據(jù)):
方式1(用于覆蓋老數(shù)據(jù)):POST請(qǐng)求 IP:9200/索引名/_doc/唯一標(biāo)識(shí)
方式2(用于覆蓋老數(shù)據(jù)):PUT請(qǐng)求 IP:9200/索引名/_doc/唯一標(biāo)識(shí)
方式3(用于修改局部數(shù)據(jù)):POST請(qǐng)求 IP:9200/索引名/_update/唯一標(biāo)識(shí)
方式1佃扼,若有id號(hào),再次執(zhí)行增文檔操作冰抢,可自動(dòng)將create操作編程update操作松嘶。
更新數(shù)據(jù)
{
"id":1,
"content":"C是世界上最好的編程語言"
}
方式2,請(qǐng)求內(nèi)容同方式1
方式3挎扰,因?yàn)橐薷木植繑?shù)據(jù)翠订,所以必須告知ES修改那塊的局部數(shù)據(jù),以下:第一層花括號(hào)和doc是固定格式遵倦。
{
"doc" : {
"content": "C是最好的編程語言"
}
}
3種方式的響應(yīng)格式一致:
{
"_index": "zs_index",
"_id": "1",
"_version": 17,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 24,
"_primary_term": 1
}
"_index": "zs_index": 表示被更新的文檔位于名為zs_index的索引中尽超。
"_id": "1": 是被更新的文檔的唯一ID。
"_version": 17: 表示該文檔的版本號(hào)已更新為17梧躺。版本號(hào)在每次更新時(shí)增加似谁,用于跟蹤文檔的變化歷史。
"result": "updated": 表示更新操作已成功執(zhí)行掠哥,文檔被更新了巩踏。
"_shards": 提供了關(guān)于更新操作涉及的分片信息。
"total": 2: 表示總共有2個(gè)分片參與了更新操作(通常是一個(gè)主分片和其副本)续搀。
"successful": 1: 表示有1個(gè)分片成功完成了更新操作塞琼。在yellow健康狀態(tài)的索引中,這意味著主分片成功了禁舷,但副本分片可能尚未同步數(shù)據(jù)彪杉。
"failed": 0: 表示沒有分片失敗毅往。
"_seq_no": 24: 是文檔在Lucene段中的序列號(hào),用于內(nèi)部跟蹤文檔版本和順序派近。
"_primary_term": 1: 主要術(shù)語(primary term)與_seq_no一起使用攀唯,確保文檔版本的一致性,特別是在主節(jié)點(diǎn)更換時(shí)渴丸。
- 查詢單條數(shù)據(jù):
GET請(qǐng)求 IP:9200/索引名/_doc/唯一標(biāo)識(shí)
{
"_index": "zs_index",
"_id": "1",
"_version": 8,
"_seq_no": 14,
"_primary_term": 1,
"found": true,
"_source": {
"id": 1,
"content": "C是世界上最好的編程語言"
}
}
"_seq_no": 14: 是文檔在Lucene段中的序列號(hào)侯嘀,用于內(nèi)部跟蹤文檔版本和順序。
"_primary_term": 1: 主要術(shù)語(primary term)與_seq_no一起使用曙强,確保文檔版本的一致性残拐,尤其是在主節(jié)點(diǎn)更換時(shí)。
"found": true: 表示Elasticsearch成功找到了指定ID的文檔碟嘴,若為false溪食,表示未找到。
"_source": 包含了文檔的實(shí)際內(nèi)容娜扇。
- 查詢多條數(shù)據(jù):
GET請(qǐng)求 IP:9200/索引名/_search
{
"took": 137,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 8,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "zs_index",
"_id": "1",
"_score": 1,
"_source": {
"id": 1,
"content": "C是世界上最好的編程語言"
}
},
{
"_index": "zs_index",
"_id": "02M0ZpABZdTHCHXLjAgN",
"_score": 1,
"_source": {
"id": 1,
"content": "C是世界上最好的編程語言"
}
}
]
}
}
"took": 137: 表示搜索操作耗費(fèi)了137毫秒错沃。
"timed_out": false: 表示搜索操作未超時(shí)。
"_shards": 提供了關(guān)于搜索操作涉及的分片信息雀瓢。
"total": 1: 表示總共有1個(gè)分片參與了搜索操作枢析。
"successful": 1: 表示所有參與的分片都成功完成了搜索。
"skipped": 0: 表示沒有分片被跳過刃麸。
"failed": 0: 表示沒有分片失敗醒叁。
"hits": 包含了搜索結(jié)果的詳細(xì)信息。
"total": {"value": 8, "relation": "eq"}: 表示符合搜索條件的文檔總數(shù)為8個(gè)泊业。
"value": 8: 具體的文檔數(shù)把沼。
"relation": "eq": 表示與總數(shù)值相等,即已經(jīng)獲取了所有匹配的文檔吁伺。
"hits"數(shù)組: 包含了每個(gè)匹配文檔的詳細(xì)信息饮睬。
每個(gè)文檔對(duì)象包括了:
"_index": "zs_index": 文檔所屬的索引名稱。
"_id": 文檔的唯一ID篮奄。
"_score": 1: 文檔的匹配分?jǐn)?shù)捆愁,此處為1(最高分)。
"_source": 包含了文檔的實(shí)際內(nèi)容窟却。
- 刪除數(shù)據(jù)
DELETE請(qǐng)求 IP:9200/索引名/_doc/唯一標(biāo)識(shí)
{
"_index": "zs_index",
"_id": "1",
"_version": 24,
"result": "not_found",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 31,
"_primary_term": 1
}
"result": "not_found": 表示更新操作未找到指定的文檔昼丑,若是deleted,表示成功刪除夸赫。
_shards": 提供了關(guān)于更新操作涉及的分片信息矾克。
"total": 2: 表示總共有 2 個(gè)分片參與了更新操作(通常是一個(gè)主分片和其副本)。
"successful": 1: 表示有 1 個(gè)分片成功完成了更新操作。在索引狀態(tài)為 yellow 時(shí)胁附,這可能意味著主分片成功了,但副本分片可能尚未同步數(shù)據(jù)滓彰。
"failed": 0: 表示沒有分片失敗控妻。
"_seq_no": 31: 是文檔在 Lucene 段中的序列號(hào),用于內(nèi)部跟蹤文檔版本和順序揭绑。
"_primary_term": 1: 主要術(shù)語(primary term)與 _seq_no 一起使用弓候,確保文檔版本的一致性,特別是在主節(jié)點(diǎn)更換時(shí)他匪。
文檔復(fù)雜查詢操作
- 通過關(guān)鍵詞查詢:
方式1:GET請(qǐng)求 IP:9200/索引名/_search?q=文檔字段名:要搜索的關(guān)鍵字
方式2:GET請(qǐng)求 IP:9200/索引名/_search
并添加請(qǐng)求body{ "query":{ "match": { "文檔字段名":"要搜索的關(guān)鍵字" } } }
{
"took": 8,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 6,
"relation": "eq"
},
"max_score": 0.074107975,
"hits": [
{
"_index": "zs_index",
"_id": "0mMsZpABZdTHCHXLZQhu",
"_score": 0.074107975,
"_source": {
"id": 1,
"content": "C是世界上最好的編程語言"
}
}
]
}
}
took: 查詢花費(fèi)的時(shí)間菇存,單位為毫秒。在這個(gè)例子中邦蜜,值為8依鸥,表示查詢執(zhí)行花費(fèi)了8毫秒時(shí)間。
timed_out: 表示查詢是否超時(shí)悼沈。在這個(gè)例子中贱迟,值為false,表示查詢未超時(shí)絮供。
_shards: 分片相關(guān)信息衣吠,包括:
total: 總分片數(shù),這里是1個(gè)分片壤靶。
successful: 成功的分片數(shù)缚俏,這里是1個(gè)分片。
skipped: 被跳過的分片數(shù)贮乳,這里是0個(gè)分片梳庆。
failed: 失敗的分片數(shù)宾尚,這里是0個(gè)分片。
hits: 查詢命中的結(jié)果集信息,包含:
total: 總命中數(shù)红省,這里是6。
max_score: 結(jié)果集中最高得分萝衩,這里是0.074107975竹挡。
hits: 包含具體的命中文檔數(shù)組。
每個(gè)文檔包含以下信息:
_index: 文檔所在的索引奖蔓。
_id: 文檔的唯一標(biāo)識(shí)符赞草。
_score: 文檔的得分。
_source: 存儲(chǔ)實(shí)際數(shù)據(jù)的字段吆鹤。
- 分頁查詢:
GET請(qǐng)求 IP:9200/索引名/_search
body體添加{ "query": { "match": { "文檔字段名":"要搜索的關(guān)鍵字" } }, "from":0, "size":2 }
其中厨疙,from為起始位置偏移量,size為每頁顯示的條數(shù)疑务。
from算法:(頁碼 -1)* size = form沾凄。
第1頁:(1 - 1)* 2 = 0梗醇,所以from為0。
第2頁:(2 - 1)* 2 = 2撒蟀,所以from為2叙谨。
響應(yīng)結(jié)果同上。
只顯示數(shù)據(jù)的部分字段:
GET請(qǐng)求 IP:9200/索引名/_search
body體添加_source項(xiàng)即可{ "query": { "match": { "文檔字段名":"要搜索的關(guān)鍵字" } }, "_source":["id"] }
響應(yīng)結(jié)果同上保屯。排序:
GET請(qǐng)求 IP:9200/索引名/_search
body體添加sort項(xiàng)即可{ "query": { "match": { "文檔字段名":"要搜索的關(guān)鍵字" } }, "sort":{ "排序的字段名":{ "order":"asc" } } }
注意手负,這個(gè)將要排序的字段,可以不被展示出來也能排序(_source控制項(xiàng))
響應(yīng)結(jié)果同上姑尺。多條件and或or查詢竟终,區(qū)間查詢
GET請(qǐng)求 IP:9200/索引名/_search
如下,需添加以下body切蟋,表示查詢content字段為C語言和(&&)C++語言(C++語言會(huì)被拆分)统捶,并且content>1(隨意測(cè)試)的數(shù)據(jù)。
若替換must為should敦姻,則表示或(or)之意瘾境。
{
"query": {
"bool": {
"must": [
{
"match": {
"content": "C語言"
}
},
{
"match": {
"content": "C++語言"
}
}
],
"filter": {
"range": {
"content": {
"gt": 1
}
}
}
}
}
}
響應(yīng)結(jié)果同上。
- 全文精準(zhǔn)匹配
GET請(qǐng)求 IP:9200/索引名/_search
仍需添加如下body{ "query":{ "match_phrase" :{ "字段名":"要搜索的關(guān)鍵字" } } }
響應(yīng)結(jié)果同上镰惦。 - 查詢到的結(jié)果高亮顯示
GET請(qǐng)求 IP:9200/索引名/_search
仍需添加如下body{ "query":{ "match_phrase" :{ "字段名":"要搜索的關(guān)鍵字" } }, "highlight":{ "fields":{ "字段名":{} } } }
響應(yīng)結(jié)果同上迷守。
聚合查詢
- 求指定字段平均值
由于聚合函數(shù)過多,逐一說明會(huì)讓篇幅變的很長(zhǎng)旺入,因此推薦看官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics.html
GET請(qǐng)求 IP:9200/索引名/_search
仍需添加如下body{ "aggs" : { "id_group_avg" : { "avg" : { "field" : "字段名" } } }, "size":0 }
其中兑凿,id_group_avg為自定義名稱,size:0表示去掉對(duì)文檔數(shù)據(jù)的返回茵瘾。
{
"took": 35,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 6,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"id_group_avg": {
"value": 1
}
}
}
took: 查詢花費(fèi)的時(shí)間礼华,單位是毫秒。這里是 35 毫秒拗秘。
timed_out: 查詢是否超時(shí)圣絮。這里顯示為 false,表示查詢?cè)谝?guī)定時(shí)間內(nèi)完成雕旨。
_shards: 這個(gè)對(duì)象提供關(guān)于查詢?cè)诜制系膱?zhí)行情況的詳細(xì)信息:
total: 總分片數(shù)扮匠。
successful: 成功完成查詢的分片數(shù)。
skipped: 跳過的分片數(shù)凡涩。
failed: 查詢失敗的分片數(shù)棒搜。
在這個(gè)例子中,總分片數(shù)為 1活箕,且成功完成了查詢力麸。
hits: 包含有關(guān)查詢匹配的文檔信息:
total: 文檔匹配的總數(shù)。
value: 匹配的文檔數(shù),這里是 6克蚂。
relation: 匹配關(guān)系闺鲸,這里是 “eq” 表示精確匹配。
max_score: 最高得分陨舱,如果不需要計(jì)算得分則為 null翠拣。
hits: 實(shí)際匹配的文檔數(shù)組。在這個(gè)例子中是空的游盲,因?yàn)闆]有具體的文檔數(shù)據(jù)。
aggregations: 聚合結(jié)果信息:
id_group_avg: 聚合名稱蛮粮,這里的值為 1益缎。具體的聚合結(jié)果會(huì)根據(jù)你的查詢和聚合定義而有所不同。
分詞與不分詞的控制
這塊由于涉及到字段的改動(dòng)然想,所以需要重新建立索引莺奔,并且添加了映射(mapping)的概念
重新建立一個(gè)people索引
PUT請(qǐng)求 IP:9200/people
再次請(qǐng)求,添加映射
IP:9200/people/_mapping
{
"properties" :{
"name" : {
"type":"text",
"index":true
},
"sex" : {
"type":"keyword",
"index":true
},
"tel" : {
"type":"keyword",
"index":false
}
}
}
上方的index指的是是否為這條數(shù)據(jù)添加索引变泄。
type是索引類型令哟,text代表支持分詞查詢(MySQL like '%kw%'),keyword代表不可分詞查詢 (MySQL = 'kw')妨蛹。
然后添加三條數(shù)據(jù)
PUT IP:9200/people/_create/1
{
"name":"張三",
"sex":"男性",
"tel":"18888888888"
}
PUT IP:9200/people/_create/2
{
"name":"李四",
"sex":"女性",
"tel":"16666666666"
}
PUT IP:9200/people/_create/3
{
"name":"王五",
"sex":"男性",
"tel":"18866668888"
}
搜索
GET IP:9200/people/_search
{
"query" :{
"match" :{
"sex" : "男" 把性去掉屏富,搜索不到數(shù)據(jù)
}
}
}
GET IP:9200/people/_search
{
"query" :{
"match" :{
"name" : "張" 把三去掉,可以搜索到數(shù)據(jù)
}
}
}
GET IP:9200/people/_search
{
"query" :{
"match" :{
"tel" : "188" 若輸入手機(jī)號(hào)前3位蛙卤,則搜不到數(shù)據(jù)狠半,輸入完整的手機(jī)號(hào),則可以搜索到數(shù)據(jù)
}
}
}
PHP Api調(diào)用
官方文檔:https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/getting-started-php.html#_installation
某些ES Api(例如創(chuàng)建索引)不能重復(fù)執(zhí)行颤难,重復(fù)執(zhí)行會(huì)報(bào)錯(cuò)神年,所以在執(zhí)行寫操作的上游做判斷,或者使用try catch行嗤。
composer require elasticsearch/elasticsearch
推薦安裝symfony/var-dumper已日,用于dd()或dump()執(zhí)行,美化輸出栅屏。
新建PHP文件飘千,以下代碼數(shù)據(jù)為公共部分。
include './vendor/autoload.php';
use Elastic\Elasticsearch\ClientBuilder;
//連接ES
$client = ClientBuilder::create()->setHosts(['192.168.0.183:9200'])->build();
//若es有密碼既琴,則需要添加一個(gè)setBasicAuthentication()方法占婉。
$client = ClientBuilder::create()->setHosts(['192.168.0.183:9200'])->setBasicAuthentication('elastic', '123456')->build();
PHP ES Api針對(duì)Index增刪改查
- 創(chuàng)建
返回bool
$response = $client->indices()->create([
'index' => 'php_index'
]);
$response->asBool();
- 查詢 判斷索引是否存在
返回bool
$response = $client->indices()->exists(['index' => 'php_index']);
dd($response->asBool());
- 查詢 查看索引相關(guān)信息
返回array
$response = $client->indices()->get(['index' => 'php_index']);
dd($response->asArray());
- 刪除
返回bool
$response = $client->indices()->delete(['index' => 'php_index']);
dd($response->asBool());
- 修改
索引作為基礎(chǔ)性的數(shù)據(jù)支撐,一般不做改動(dòng)甫恩。
PHP ES Api針對(duì)Mapping增刪改查
- 類型可參考官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html
- 增 創(chuàng)建索引后
返回bool
$params = [
'index' => 'php_index',
'body' => [
'properties' => [
'name' => [
'type' => 'text',
],
]
]
];
$response = $client->indices()->putMapping($params);
dd($response->asBool());
- 增 創(chuàng)建索引時(shí)
返回bool
$params = [
'index' => 'php_index',
'body' => [
'mappings' => [
'properties' => [
'title' => [
'type' => 'text',
],
'content' => [
'type' => 'text',
],
]
]
]
];
$response = $client->indices()->create($params);
dd($response->asBool());
- 查 所有索引
返回?cái)?shù)組
$response = $client->indices()->getMapping();
dd($response->asArray());
- 查 指定索引
返回?cái)?shù)組
$response = $client->indices()->getMapping(['index' => 'php_index']);
dd($response->asArray());
- 刪
請(qǐng)直接刪除索引逆济。 - 改
請(qǐng)重新建立索引,在新索引基礎(chǔ)上做映射的修改。
PHP ES Api針對(duì)Doc增刪改
- 索引與映射如下:
準(zhǔn)備四個(gè)直轄市的名稱奖慌,簡(jiǎn)介抛虫,人口和面積大小。
$params = [
'index' => 'php_index',
'body' => [
'mappings' => [
'properties' => [
'city' => [
'type' => 'keyword',
],
'description' => [
'type' => 'text',
],
'population' => [
'type' => 'integer'
],
'area' => [
'type' => 'integer'
],
]
]
]
];
$response = $client->indices()->create($params);
dd($response->asArray());
- 增 單條 請(qǐng)記憶這4個(gè)直轄市的數(shù)據(jù)保存格式简僧,下文基本每個(gè)演示都要用
一級(jí)數(shù)組下有個(gè)id屬性建椰,若省去,ES會(huì)默認(rèn)給這條數(shù)據(jù)加一個(gè)id岛马。不推薦棉姐。推薦使用MySQL的數(shù)據(jù)id作為ES的id。
返回bool
$params = [
'index' => 'php_index',
'id' => 1,
'body' => [
'id' => 1,
'city' => '北京市',
'description' => '北京市(Beijing)啦逆,簡(jiǎn)稱“京”伞矩,古稱燕京、北平夏志,是中華人民共和國首都乃坤、直轄市、國家中心城市沟蔑、超大城市湿诊, 國務(wù)院批復(fù)確定的中國政治中心、文化中心瘦材、國際交往中心厅须、科技創(chuàng)新中心, 中國歷史文化名城和古都之一宇色,世界一線城市',
'population' => '2186',
'area' => '16411',
]
];
$response = $client->index($params);
dd($response->asBool());
再增加3條數(shù)據(jù)
$params = [
'index' => 'php_index',
'id' => 2,
'body' => [
'id' => 2,
'city' => '上海市',
'description' => '上海市(Shanghai City)九杂,簡(jiǎn)稱“滬” ,別稱“申”宣蠕,中華人民共和國直轄市例隆、國家中心城市、超大城市抢蚀、上海大都市圈核心城市镀层、國家歷史文化名城 [206],是中國共產(chǎn)黨的誕生地皿曲。上海市入圍世界Alpha+城市唱逢, 基本建成國際經(jīng)濟(jì)、金融屋休、貿(mào)易坞古、航運(yùn)中心,形成具有全球影響力的科技創(chuàng)新中心基本框架劫樟。截至2022年12月底痪枫,上海市轄16個(gè)區(qū)织堂,107個(gè)街道、106個(gè)鎮(zhèn)奶陈、2個(gè)鄉(xiāng)易阳。',
'population' => '2487',
'area' => '6341',
]
];
$params = [
'index' => 'php_index',
'id' => 3,
'body' => [
'id' => 3,
'city' => '天津市',
'description' => '天津市(Tianjin City),簡(jiǎn)稱“津”吃粒,別稱津沽潦俺、津門,是中華人民共和國省級(jí)行政區(qū)徐勃、直轄市事示、國家中心城市、超大城市 [222]僻肖,地處中華人民共和國華北地區(qū)很魂,海河流域下游,東臨渤海檐涝,北依燕山,西靠首都北京市法挨,其余均與河北省相鄰谁榜。截至2023年10月,天津市共轄16個(gè)區(qū)凡纳。',
'population' => '1364',
'area' => '11966',
]
];
$params = [
'index' => 'php_index',
'id' => 4,
'body' => [
'id' => 4,
'city' => '重慶市',
'description' => '重慶市窃植,簡(jiǎn)稱“渝”, 別稱山城荐糜、江城巷怜,是中華人民共和國直轄市、國家中心城市暴氏、超大城市延塑,國務(wù)院批復(fù)的國家重要中心城市之一、長(zhǎng)江上游地區(qū)經(jīng)濟(jì)中心答渔, 國際消費(fèi)中心城市关带,全國先進(jìn)制造業(yè)基地、西部金融中心沼撕、西部科技創(chuàng)新中心宋雏、 國際性綜合交通樞紐城市和對(duì)外開放門戶,轄38個(gè)區(qū)縣',
'population' => '3191',
'area' => '82400',
]
];
- 增 多條
返回?cái)?shù)組
//假設(shè)MySQL查詢出來的數(shù)據(jù)如下
$mysql_data = [
[
'id' => 1024,
'city' => 'xx市',
'description' => 'xxxx',
'population' => '6666',
'area' => '6666',
],
[
'id' => 1025,
'city' => 'yy市',
'description' => 'yyyy',
'population' => '8888',
'area' => '8888',
]
];
//由于ES插入的要求务豺,需要將插入數(shù)據(jù)的格式轉(zhuǎn)化磨总,為此可以封裝一個(gè)方法
function esBatchInsert($index_name, $mysql_data) {
$params = [];
foreach($mysql_data as $v) {
$params['body'][] = ['index' => ['_index' => $index_name, '_id' => $v['id']],];
$params['body'][] = $v;
}
return $params;
}
$response = $client->bulk(esBatchInsert('php_index', $mysql_data));
dd($response->asArray());
可根據(jù)返回的數(shù)據(jù)再次循環(huán),排查失敗掉的漏網(wǎng)之魚
- 刪 單條
返回bool
$params = [
'index' => 'php_index',
'id' => '1025'
];
$response = $client->delete($params);
dd($response->asBool());
- 刪 多條
方式1:
返回mixed
for($i = 1000; $i < 1050; $i++) { //模擬要?jiǎng)h除這些數(shù)據(jù)
$params = [
'index' => 'php_index',
'id' => $i
];
if(! $client->exists($params)->asBool()) {
continue;
}
$response = $client->delete($params)->asBool();
if(! $response) {
//若刪除失敗笼沥,請(qǐng)?zhí)砑悠渌僮黩窖啵涗浫罩净虼嫒腙?duì)列娶牌,進(jìn)行重試或者人工介入
}
}
方式2:
返回mixed
for($i = 1000; $i < 1050; $i++) { //模擬要?jiǎng)h除這些數(shù)據(jù)
$params['body'][] = [
'delete' => [
'_index' => 'php_index',
'_id' => $i,
]
];
}
$response = $client->bulk($params)->asArray();
if ($response['errors']) {
foreach ($response['items'] as $item) {
if (isset($item['delete']['status']) && ($item['delete']['status'] != 200)) {
//若刪除失敗,請(qǐng)?zhí)砑悠渌僮髁谑恚涗浫罩净虼嫒腙?duì)列裙戏,進(jìn)行重試或者人工介入
}
}
} else {
echo "批量刪除成功!";
}
- 刪 文檔的某個(gè)字段
返回bool
$params = [
'index' => 'php_index',
'id' => 1,
'body' => [
'script' => [
'source' => 'ctx._source.remove(params.field)',
'params' => [
'field' => '要?jiǎng)h除的字段名'
]
]
]
];
$response = $client->update($params);
dd($response->asBool());
- 改 直接修改
返回bool
$params = [
'index' => 'php_index',
'id' => 1,
'body' => [
'doc' => [
'city' => '北京' //這里是要修改的字段厕诡,把北京市改為北京
]
]
];
$response = $client->update($params);
dd($response->asBool());
- 改 自增
返回bool
官方文檔演示有誤累榜,請(qǐng)按照以下正確寫法。
$params = [
'index' => 'php_index',
'id' => 1,
'body' => [
'script' => [
//表達(dá)式
'source' => 'ctx._source.population += params.population', //給北京人口加4萬灵嫌,population為自定義文檔字段壹罚,其余字符固定寫法。
//表達(dá)式所使用的變量
'params' => [
'population' => 4
],
],
]
];
$response = $client->update($params);
dd($response->asBool());
- 改 若文檔不存在寿羞,則插入
$params = [
'index' => 'php_index',
'id' => 60, //若id對(duì)應(yīng)的文檔不存在猖凛,則利用upsert段的數(shù)據(jù),重新生成一個(gè)id為60的文檔绪穆。
'body' => [
'doc' => [
'city' => '臺(tái)北市'
],
'upsert' => [
'append_field' => 1
],
]
];
$response = $client->update($params);
dd($response->asBool());
- 改 批量
//假設(shè)以下數(shù)據(jù)時(shí)數(shù)據(jù)表中查詢出來的字段辨泳,要修改以下內(nèi)容
$mysql_data = [
['id' => 1, 'city' => '北京'],
['id' => 2, 'city' => '上海'],
];
//可以封裝一個(gè)方法,格式化數(shù)據(jù)
function esBatchUpdate($index_name, $update_data) {
if(! $update_data) {
return [];
}
$arr = [];
foreach($update_data as $v) {
$arr[] = ['update' => ['_index' => $index_name, '_id' => $v['id']]];
unset($v['id']);
$arr[] = ['doc' => $v];
}
return ['body' => $arr];
}
$response = $client->bulk(esBatchUpdate('php_index', $mysql_data));
$response = $response->asArray();
//處理
if ($response['errors']) {
foreach ($response['items'] as $item) {
if (isset($item['update']['status']) && ($item['update']['status'] != 200)) {
//若刪除失敗玖院,請(qǐng)?zhí)砑悠渌僮鞑ず欤涗浫罩净虼嫒腙?duì)列,進(jìn)行重試或者人工介入
}
}
} else {
echo "批量刪除成功难菌!";
}
- 改 追加新的字段
$params = [
'index' => 'php_index',
'id' => '1',
'body' => [
'doc' => [
'new_field' => 'new_value'
],
]
];
$response = $client->update($params);
- 改 刪除某些字段
返回bool
$params = [
'index' => 'php_index',
'id' => 1,
'body' => [
'script' => [
'source' => 'ctx._source.remove(params.field)',
'params' => [
'field' => '要?jiǎng)h除的字段名'
]
]
]
];
$response = $client->update($params);
dd($response->asBool());
PHP ES Api針對(duì)Doc高級(jí)查詢
查詢關(guān)鍵詞官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/term-level-queries.html
- 指定id查找
返回string
$params = [
'index' => 'php_index',
'id' => 1,
];
$response = $client->get($params);
echo $response->asString();
得到以下結(jié)果
{
"_index": "php_index",
"_id": "1",
"_version": 1,
"_seq_no": 0,
"_primary_term": 1,
"found": true,
"_source": {
"id": 1,
"city": "北京市",
"description": "北京市(Beijing)试溯,簡(jiǎn)稱“京”,古稱燕京郊酒、北平遇绞,是中華人民共和國首都、直轄市燎窘、國家中心城市摹闽、超大城市, 國務(wù)院批復(fù)確定的中國政治中心荠耽、文化中心钩骇、國際交往中心、科技創(chuàng)新中心铝量, 中國歷史文化名城和古都之一倘屹,世界一線城市",
"population": "2186",
"area": "16411"
}
}
- 查找全部
返回array
$response['hits']['total']['value']可獲取條數(shù)
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'match_all' => new StdClass
]
]
];
$response = $client->search($params);
dd($response->asArray());
- 指定指定部分id的數(shù)據(jù)。
返回?cái)?shù)組
$response['hits']['total']['value']可獲取條數(shù)
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'ids' => [
'values' => [1, 2]
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
- 分頁查詢
返回?cái)?shù)組
//傳輸?shù)捻摯a
$page = 2;
$size = 2;
//偏移量算法
$offset = ($page -1 ) * $size;
$params = [
'index' => 'php_index',
'body' => [
'from' => $offset,
'size' => $size,
// 可以添加其他查詢條件
'query' => [
'match_all' => new \stdClass()
]
]
];
$response = $client->search($params);
dd($response->asArray());
- 返回指定字段
返回?cái)?shù)組
$params = [
'index' => 'php_index',
'body' => [
'_source' => ['description'], //自定義字段
'query' => [
'match_all' => new \stdClass()
]
]
];
$response = $client->search($params);
dd($response->asArray());
- 判斷是否存在
返回bool
$params = [
'index' => 'php_index',
'id' => 10
];
$response = $client->exists($params);
- 獲取條數(shù)
返回int
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'match_all' => new StdClass
]
]
];
$response = $client->count($params);
dd($response->asArray()['count'] ?? 0);
- 高亮查詢(類比百度詞條對(duì)關(guān)鍵字的標(biāo)紅行為)
返回string
echo "<style>em{color:red}</style>";
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'match' => [
'description' => '北京' //返回該字段含有北京或北或京的文字慢叨。
]
],
'highlight' => [
'fields' => [
'city' => ['pre_tags' => ['<em>'], 'post_tags' => ['</em>'],], //配置要高亮的字段
'description' => ['pre_tags' => ['<em>'], 'post_tags' => ['</em>'],] //配置要高亮的字段
]
]
]
];
$response = $client->search($params);
print_r($response->asString());
返回格式如下纽匙,具體要用那個(gè)字段,看具體需求
<style>em{color:red}</style>
{
"took":13,
"timed_out":false,
"_shards":{
"total":1,
"successful":1,
"skipped":0,
"failed":0
},
"hits":{
"total":{
"value":2,
"relation":"eq"
},
"max_score":2.9070516,
"hits":[
{
"_index":"php_index",
"_id":"1",
"_score":2.9070516,
"_source":{
"id":1,
"city":"北京",
"description":"北京市(Beijing)拍谐,簡(jiǎn)稱“京”烛缔,古稱燕京馏段、北平,是中華人民共和國首都践瓷、直轄市院喜、國家中心城市、超大城市晕翠, 國務(wù)院批復(fù)確定的中國政治中心喷舀、文化中心、國際交往中心淋肾、科技創(chuàng)新中心硫麻, 中國歷史文化名城和古都之一,世界一線城市",
"population":2198,
"area":"16411",
"new_field":"new_value"
},
"highlight":{
"description":["<em>北</em><em>京</em>市(Beijing)樊卓,簡(jiǎn)稱“<em>京</em>”拿愧,古稱燕<em>京</em>、<em>北</em>平碌尔,是中華人民共和國首都浇辜、直轄市、國家中心城市唾戚、超大城市奢赂, 國務(wù)院批復(fù)確定的中國政治中心、文化中心颈走、國際交往中心、科技創(chuàng)新中心咱士, 中國歷史文化名城和古都之一"]
}
},
{
"_index":"php_index",
"_id":"3",
"_score":2.5460577,
"_source":{
"id":3,
"city":"天津市",
"description":"天津市(Tianjin City)立由,簡(jiǎn)稱“津”,別稱津沽序厉、津門锐膜,是中華人民共和國省級(jí)行政區(qū)、直轄市弛房、國家中心城市道盏、超大城市 [222],地處中華人民共和國華北地區(qū)文捶,海河流域下游荷逞,東臨渤海,北依燕山粹排,西靠首都北京市种远,其余均與河北省相鄰。截至2023年10月顽耳,天津市共轄16個(gè)區(qū)坠敷。",
"population":"1364",
"area":"11966"
},
"highlight":{
"description":["天津市(Tianjin City)妙同,簡(jiǎn)稱“津”,別稱津沽膝迎、津門粥帚,是中華人民共和國省級(jí)行政區(qū)、直轄市限次、國家中心城市芒涡、超大城市 [222],地處中華人民共和國華<em>北</em>地區(qū)掂恕,海河流域下游拖陆,東臨渤海,<em>北</em>依燕山懊亡,西靠首都<em>北</em><em>京</em>市","依啰,其余均與河<em>北</em>省相鄰。"]
}
}
]
}
}
- 限量 可參考分頁邏輯(類比MySQL limit)
返回array
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'match_all' => new stdClass
],
'from' => 0,
'size' => 1,
]
];
$response = $client->search($params);
dd($response->asArray());
- 定值查找 (類比MySQL wher filed = ‘kw’)
keyword 或 integer 等非分詞字段:可用 term 精確匹配店枣。如果字段是 text 類型速警,那么 term 查詢無法找到預(yù)期的匹配結(jié)果。
text 類型并且你想要精確匹配鸯两,可以使用 match_phrase 查詢
方式1 針對(duì)integer字段的精準(zhǔn)匹配
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'term' => [
'city' => '北京市' //北京或北或京無法查詢出指定數(shù)據(jù)
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
- 分詞查找(類比MySQL where filed like '%kw%' or filed like '%k%' or filed like '%w%')
方式1
返回array
這種方式僅支持text類型
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'match' => [
'description' => '北京'
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
方式2
返回array
非text類型闷旧,可手動(dòng)分詞
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'bool' => [
'should' => [ //or
[
'match' => ['city' => '北京']
],
[
'match' => ['city' => '北京市']
]
],
'minimum_should_match' => 1
//minimum_should_match 設(shè)置為 1,表示至少需要匹配一個(gè) should 子句中的條件
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
- 模糊匹配 (類比MySQL where filed like '%kw%')wildcard性能可能不如其它類型的查詢钧唐,如match查詢忙灼,因?yàn)閣ildcard查詢需要對(duì)每個(gè)文檔的字段值進(jìn)行模式匹配
方式1,針對(duì)keyword mapping
返回array
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'wildcard' => [
'city' => '*北京*' //*表示任意字符钝侠,?表示任意一個(gè)字符
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
方式2该园,針對(duì)text mapping,并非嚴(yán)格意義上的MySQL where filed like '%kw%'帅韧,而是 where filed like '%kw%' or filed like '%k%' or filed like '%w%'
返回array
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'match' => [
'description' => '北京'
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
- 前綴查找 (類比MySQL where filed like 'kw%')針對(duì)keyword類型的字段有效
返回array
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'prefix' => [
'city' => '北'
]
]
]
];
$response = $client->search($params);
- 后綴查找 (類比MySQL where filed like '%kw')針對(duì)keyword字段有效
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'wildcard' => [
'city' => '*京市'
]
]
]
];
$response = $client->search($params);
- 區(qū)間查找(類比MySQL where field <里初、<=、>忽舟、>=双妨、between)
返回array
<是lt、<=是lte叮阅、>是gt刁品、>=是gte
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'range' => [
'area' => [ //面積大于1000平方千米的城市
'gt' => 1000
]
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
返回array
between
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'range' => [
'area' => [ //獲取面積大于1000平方千米,但在10000平方千米以內(nèi)的城市數(shù)據(jù)
'gt' => 1000,
'lt' => 10000,
]
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
- 正則匹配(類比MySQL where field regexp 'xxx')針對(duì)keyword字段有效
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'regexp' => [
'city' => '.*北京.*' //搜索包含北京關(guān)鍵字的字段
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
.*: 匹配任意數(shù)量的任意字符
.: 匹配任意單個(gè)字符浩姥。
*: 匹配前面的元素零次或多次哑诊。
+: 匹配前面的元素一次或多次。
?: 匹配前面的元素零次或一次及刻。
^: 匹配字符串的開頭镀裤。
$: 匹配字符串的結(jié)尾竞阐。
[...]: 匹配方括號(hào)中的任意字符。
{n}: 匹配前面的元素恰好 n 次暑劝。
{n,}: 匹配前面的元素至少 n 次骆莹。
{n,m}: 匹配前面的元素至少 n 次,但不超過 m 次担猛。
- 取反查找(類比MySQL where filed != 'kw')針對(duì)text類型的字段無效
返回bool
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'bool' => [
'must_not' => [
'term' => [
'city' => '北京市' //返回不是北京市的數(shù)據(jù)
]
]
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'bool' => [
'must_not' => [
'range' => [
'area' => [ //面積不小于1000平方千米的城市
'lt' => 1000
]
]
]
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
- 多條件and查找(類比MySQL where expression1 and expression2)
返回array
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'bool' => [
'must' => [ //返回city字段是北京市幕垦,并且描述帶有首都的數(shù)據(jù)
['term' => ['city' => '北京市']],
['match' => ['description' => '首都']],
]
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
- 多條件or查找(類比MySQL where expression1 or expression2)
返回array
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'bool' => [
'should' => [ //查詢城市名北京市,或者描述含有滬的描述內(nèi)容
['term' => ['city' => '北京市']],
['match' => ['description' => '滬']],
]
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
- and 和 or 共同使用
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'bool' => [ //查詢城市名為北京市或上海市傅联,并且描述帶有京字的數(shù)據(jù)
'must' => [
[
'bool' => [
'should' => [
['term' => ['city' => '北京市']],
['term' => ['city' => '上海市']]
]
]
],
['match' => ['description' => '京']]
]
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
- 排序(類比MySQL Order By)
單字段排序
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'match_all' => new StdClass,
],
'sort' => [ //四個(gè)直轄市數(shù)據(jù)按照區(qū)域大小排名
['area' => ['order' => 'asc']] //asc或desc
]
]
];
$response = $client->search($params);
dd($response->asArray());
多字段排序
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'match_all' => new StdClass,
],
'sort' => [ //區(qū)域按照降序先改,人口按照升序排,條件不會(huì)沖突蒸走,回想MySQL order by那樣仇奶,合并處理。
['area' => ['order' => 'asc']], //asc或desc
['population' => ['order' => 'desc']], //asc或desc
]
]
];
- 聚合函數(shù)(類比MySQL聚合函數(shù))
返回bool
$params = [
'index' => 'php_index',
'body' => [
'size' => 0, // 設(shè)置為0表示不返回實(shí)際的文檔比驻,僅返回聚合結(jié)果
'aggs' => [
'population_data' => [ //這個(gè)key為自定義名稱
'avg' => [ //返回4個(gè)直轄市平均人口
'field' => 'population'
]
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
avg : 平均值
sum :總和
min : 最小值
max :最大值
沒有count该溯。
- 分組(類比MySQL Group By)
返回string
$params = [
'index' => 'php_index',
'body' => [
'size' => 0, // 不返回文檔,只返回聚合結(jié)果
'aggs' => [
'city_group' => [ //自定義名稱
'terms' => [
'field' => 'city',
'size' => 10 // 聚合結(jié)果的數(shù)量限制
]
]
]
]
];
$response = $client->search($params)->asArray();
$aggregations = $response['aggregations']['city_group']['buckets'];
foreach ($aggregations as $bucket) {
echo "城市名:" . $bucket['key'] . " - 本組組對(duì)應(yīng)的數(shù)量:" . $bucket['doc_count'] . "\n";
}
城市名:上海市 - 本組組對(duì)應(yīng)的數(shù)量:1
城市名:北京市 - 本組組對(duì)應(yīng)的數(shù)量:1
城市名:天津市 - 本組組對(duì)應(yīng)的數(shù)量:1
城市名:重慶市 - 本組組對(duì)應(yīng)的數(shù)量:1
- 合并(類比MySQL union)
用PHP array_merge實(shí)現(xiàn)吧别惦,這對(duì)于ES不適用狈茉。 - 指定數(shù)據(jù)靠前(類比競(jìng)價(jià)排名)
返回array
個(gè)人還是推薦使用自定義字段,因?yàn)閇'hits']['_score']字段得出來分?jǐn)?shù)不可控掸掸。
搜索城市氯庆,原先是北京靠前,現(xiàn)在通過修改權(quán)重扰付,使其上旱闱纾靠前
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'function_score' => [
'query' => [
'bool' => [
'should' => [
['term' => ['city' => '北京市']],
['match' => ['description' => '滬']]
]
]
],
'functions' => [
[
'filter' => [
'match' => ['description' => '滬']
],
'weight' => 2 // 增加包含“滬”的文檔的權(quán)重
]
],
'boost_mode' => 'sum'
]
],
'sort' => [
'_score' => [
'order' => 'desc' // 按照得分降序排序
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
boost_mode設(shè)定了如何將查詢的基礎(chǔ)得分(由 query 部分確定)與功能得分(由 functions 部分計(jì)算)進(jìn)行組合。以下是幾種常用的 boost_mode 設(shè)置:
multiply: 基礎(chǔ)得分與功能得分相乘悯周。
replace: 功能得分替代基礎(chǔ)得分。
sum: 基礎(chǔ)得分與功能得分相加陪竿。
avg: 基礎(chǔ)得分與功能得分的平均值禽翼。
max: 取基礎(chǔ)得分與功能得分中的最大值。
Painless
- 極簡(jiǎn)概括:是一種簡(jiǎn)單族跛、安全的闰挡、服務(wù)于Elasticsearch的腳本語言。類比Redis或Nginx中的Lua礁哄,某些組件嵌入腳本語言用于實(shí)現(xiàn)復(fù)雜的邏輯,這并不罕見。
- 官方文檔:https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-guide.html
- 使用場(chǎng)景:針對(duì)ES证膨,例如上文在更新文檔中,請(qǐng)求文檔script段中的source段之拨,都用的painless表達(dá)式。
- 額外補(bǔ)充:由于painless語法內(nèi)容過多咧叭,且比較簡(jiǎn)單蚀乔,整個(gè)記錄下來需要2萬字,成本問題菲茬,因此讀者推薦看手冊(cè)吉挣。
- 簡(jiǎn)單舉例:
//counter子對(duì)岸自增
ctx._source.counter += params.count
//if else 判斷
if (ctx._source.someField > 10) {
ctx._source.anotherField = ctx._source.someField * params.multiplier;
} else {
ctx._source.anotherField = params.defaultValue;
}
IK中問分詞與高級(jí)索引創(chuàng)建
- 使用理由:ES默認(rèn)的分詞器對(duì)中文不友好,英文分詞器會(huì)把中文每個(gè)字分開婉弹,因此需要專門的中文分詞器睬魂。
- 分詞器的服務(wù)對(duì)象是映射,而不是索引镀赌。
- 安裝:
關(guān)閉ES
執(zhí)行以下代碼氯哮,注意版本號(hào)的問題
bin/elasticsearch-plugin install https://get.infini.cloud/elasticsearch/analysis-ik/8.14.1
進(jìn)入交互界面輸入Y。
之后啟動(dòng)ES
- ik_max_word與ik_smart分詞精度控制演示:
演示分詞:
GET IP:9200/_analyze
傳入以下內(nèi)容
{
"text":"射雕英雄傳",
"analyzer":"ik_smart"
}
返回
{
"tokens": [
{
"token": "射雕英雄傳",
"start_offset": 0,
"end_offset": 5,
"type": "CN_WORD",
"position": 0
}
]
}
若使用ik_max_word
{
"text":"射雕英雄傳",
"analyzer":"ik_max_word"
}
則返回
{
"tokens": [
{
"token": "射雕英雄傳",
"start_offset": 0,
"end_offset": 5,
"type": "CN_WORD",
"position": 0
},
{
"token": "射雕",
"start_offset": 0,
"end_offset": 2,
"type": "CN_WORD",
"position": 1
},
{
"token": "英雄傳",
"start_offset": 2,
"end_offset": 5,
"type": "CN_WORD",
"position": 2
},
{
"token": "英雄",
"start_offset": 2,
"end_offset": 4,
"type": "CN_WORD",
"position": 3
},
{
"token": "傳",
"start_offset": 4,
"end_offset": 5,
"type": "CN_CHAR",
"position": 4
}
]
}
- 配置自定義分詞:
有些場(chǎng)景佩脊,有很多的專業(yè)用語蛙粘,但是IK分詞器把它拆分開,就顯得不是很精準(zhǔn)威彰,因此可以添加自定義分詞解決出牧。
vim ES安裝目錄/config/analysis-ik/IKAnalyzer.cfg.xml
在<entry key="ext_dict"></entry>的雙標(biāo)簽中間寫入文件名,例如
<entry key="ext_dict">self_words.dic</entry>
vim self_words.dic
逐行添加自定義詞匯
重啟ES歇盼。
- PHP使用:
返回bool
$params = [
'index' => 'test_index',
'body' => [
'settings' => [
'analysis' => [
'analyzer' => [
'analyzer_ik_max_word' => [
'type' => 'ik_max_word' //ik分詞器內(nèi)置關(guān)鍵配置舔痕,更多的分詞結(jié)果
],
'analyzer_ik_smart' => [
'type' => 'ik_smart' //ik分詞器內(nèi)置關(guān)鍵配置,更快的分詞結(jié)果
]
]
]
],
'mappings' => [
'properties' => [
'content' => [
'type' => 'text',
'analyzer' => 'analyzer_ik_smart', // 設(shè)置索引時(shí)的分詞器
'search_analyzer' => 'analyzer_ik_smart' // 設(shè)置搜索時(shí)的分詞器
]
]
]
]
];
$response = $client->indices()->delete(['index' => 'test_index']);
dump($response->asBool());
- 進(jìn)階用法豹缀,添加過濾(不生效):
返回bool
這里嘗試創(chuàng)建了一個(gè)更復(fù)雜的索引伯复,添加了過濾器,但是不生效邢笙,不知道是那里的問題啸如。
如下,按照以下索引的配置氮惯,過濾后的結(jié)果叮雳,應(yīng)當(dāng)是"C世界上最好編程語言",然后再分詞妇汗,可卻不生效帘不。
GET IP:9200/test_index/_analyze
{
"analyzer":"self_ik_max_word",
"text" : "PHP是世界上最好的編程語言"
}
$params = [
'index' => 'test_index', // 指定要?jiǎng)?chuàng)建的索引名稱
'body' => [
'settings' => [ // 配置索引的設(shè)置
'analysis' => [ // 分析器設(shè)置
'char_filter' => [ // 字符過濾器設(shè)置
'self_char_filter' => [ // 自定義字符過濾器名稱
'type' => 'mapping', // 過濾器類型為映射
'mappings' => ['PHP => C'] // 替換分詞的字符
]
],
'filter' => [ // 過濾器設(shè)置
'self_filter' => [ // 自定義停用詞過濾器名稱
'type' => 'stop', // 過濾器類型為停用詞
'stopwords' => ['是', '的'] // 停用詞列表
]
],
'analyzer' => [ // 分析器設(shè)置
'self_ik_max_word' => [ // IK 分詞器名稱
'type' => 'ik_max_word', // 使用 IK 分詞器的最大分詞模式
'char_filter' => ['html_strip', 'self_char_filter'], // html_strip過濾器會(huì)把html標(biāo)簽忽略,但html轉(zhuǎn)義字符仍舊生效( 仍舊是空格)杨箭,且會(huì)把<br/>轉(zhuǎn)化為\n
'filter' => ['lowercase', 'self_filter'] //lowercase過濾器是將大寫字母變?yōu)樾? ],
'self_ik_smart' => [ // IK 分詞器名稱
'type' => 'ik_smart', // 使用 IK 分詞器的快速分詞模式
'char_filter' => ['html_strip', 'self_char_filter'], // html_strip過濾器會(huì)把html標(biāo)簽忽略寞焙,但html轉(zhuǎn)義字符仍舊生效( 仍舊是空格),且會(huì)把<br/>轉(zhuǎn)化為\n
'filter' => ['lowercase', 'self_filter'] //lowercase過濾器是將大寫字母變?yōu)樾? ]
]
]
],
'mappings' => [ // 配置索引的映射
'properties' => [ // 文檔字段的屬性設(shè)置
'content' => [ // 文檔中的字段名稱
'type' => 'text', // 字段類型為文本
'analyzer' => 'self_ik_max_word', // 設(shè)置索引時(shí)的分詞器
'search_analyzer' => 'self_ik_max_word' // 設(shè)置搜索時(shí)的分詞器
]
]
]
]
];
$response = $client->indices()->create($params);
dd($response->asBool());
ELK
- 概念:ES結(jié)合LK作為ELK(Elasticsearch(搜索), Logstash(采集轉(zhuǎn)換), Kibana(分析))組合,可用于實(shí)時(shí)監(jiān)控捣郊、分析和可視化大量日志和事件數(shù)據(jù)辽狈,如系統(tǒng)日志、應(yīng)用程序日志模她、網(wǎng)絡(luò)流量日志等稻艰。
- 構(gòu)成
- Elasticsearch:一個(gè)分布式搜索引擎,提供強(qiáng)大的搜索功能和實(shí)時(shí)的數(shù)據(jù)分析能力侈净。
- Logstash:一個(gè)數(shù)據(jù)處理管道尊勿,用于收集、解析和轉(zhuǎn)發(fā)日志數(shù)據(jù)畜侦。
- Kibana:一個(gè)數(shù)據(jù)可視化工具元扔,幫助用戶通過圖形化界面查看和分析 Elasticsearch 中的數(shù)據(jù)。
- 作用:
- 日志管理:集中化日志收集:通過Logstash收集來自不同系統(tǒng)和應(yīng)用的日志旋膳,統(tǒng)一存儲(chǔ)在Elasticsearch中澎语。
- 日志分析:利用Kibana對(duì)日志數(shù)據(jù)進(jìn)行實(shí)時(shí)分析和可視化,幫助發(fā)現(xiàn)系統(tǒng)問題和異常验懊。
- 實(shí)時(shí)監(jiān)控:跟蹤應(yīng)用程序的性能指標(biāo)擅羞,實(shí)時(shí)查看應(yīng)用的健康狀況。
- 性能瓶頸檢測(cè):通過分析日志數(shù)據(jù)义图,識(shí)別和解決性能瓶頸减俏。
- 安全事件分析:監(jiān)控和分析系統(tǒng)中的安全事件,檢測(cè)異常行為碱工。
- 合規(guī)性審計(jì):記錄和分析系統(tǒng)日志娃承,以滿足合規(guī)性要求。
- 數(shù)據(jù)可視化:通過Kibana創(chuàng)建各種圖表和儀表盤怕篷,幫助業(yè)務(wù)分析師理解數(shù)據(jù)趨勢(shì)和模式历筝。
- 用戶行為分析:分析用戶的操作日志,優(yōu)化用戶體驗(yàn)和產(chǎn)品設(shè)計(jì)廊谓。
- 服務(wù)器監(jiān)控:跟蹤服務(wù)器的性能指標(biāo)梳猪,如CPU使用率、內(nèi)存使用情況和磁盤空間蒸痹。
- 應(yīng)用狀態(tài)監(jiān)控:監(jiān)控應(yīng)用程序的運(yùn)行狀態(tài)和日志春弥,以確保正常運(yùn)行。
- 問題診斷:利用Elasticsearch存儲(chǔ)的日志數(shù)據(jù)电抚,快速定位和解決系統(tǒng)故障。
- 根因分析:分析相關(guān)日志竖共,幫助找到問題的根本原因蝙叛。
- 對(duì)于PHP而言:幾乎用不到,這是Java和大數(shù)據(jù)方向的公给。
Kibana
- 極簡(jiǎn)概括:開源的可視化控制ES的組件借帘。
- 官方文檔:https://www.elastic.co/guide/en/kibana/current/index.html
- 安裝:
保證ES服務(wù)已啟動(dòng)蜘渣。
防火墻開啟5601端口
firewall-cmd --add-port=5601/tcp --zone=public --permanent
systemctl restart firewalld
下載與解壓
curl -O https://artifacts.elastic.co/downloads/kibana/kibana-8.14.1-linux-x86_64.tar.gz
tar zxf kibana-8.14.1-linux-x86_64.tar.gz
權(quán)限配置
chown -R es:es kibana-8.14.1
切換用戶
su es
kibana不支持elastic用戶,所以需要?jiǎng)?chuàng)建新用戶肺然,并賦予超級(jí)管理員角色蔫缸,并賦予kibana_system角色
elasticsearch-users useradd zs
elasticsearch-users roles -a superuser zs
少了這一步報(bào)錯(cuò),讓我搞了4個(gè)小時(shí)际起。
elasticsearch-users roles -a kibana_system zs
修改配置
vim kibana-8.14.1/config/kibana.yml
elasticsearch.username: "zs"
elasticsearch.password: "123456"
elasticsearch.hosts: ["ES IP:9200"]
i18n.locale: "zh-CN"
啟動(dòng)
kibana-8.14.1/bin/kibana
過2分鐘后拾碌,訪問http://IP:5601
4種和數(shù)據(jù)庫同步方案
- 不妨先講一講業(yè)務(wù)層是怎么使用ES的讀功能的:
以電商系統(tǒng)為例,用到ES的原因街望,一個(gè)是商品數(shù)量龐大校翔,一個(gè)是分詞有助于展示更好的結(jié)果,上架的商品因?yàn)殛P(guān)鍵詞誤差搜不到灾前,這就是損失防症。
例如商品列表數(shù)據(jù)的展示,可將價(jià)格哎甲,名稱蔫敲,描述,主圖片炭玫,標(biāo)簽奈嘿,id等其他數(shù)據(jù)存入ES,然后展示础嫡。
當(dāng)用戶點(diǎn)擊某個(gè)商品時(shí)指么,根據(jù)id進(jìn)行哈希運(yùn)算,獲取商品數(shù)據(jù)在那個(gè)MySQL分表中榴鼎,利用id主鍵索引極速查詢的特性伯诬,快速獲取商品數(shù)據(jù)。 - 同步雙寫:MySQL和ES同步更新
- 優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單巫财,實(shí)時(shí)性高盗似。
- 缺點(diǎn):耦合度高,其中一個(gè)組件異称较睿可能會(huì)影響另一個(gè)赫舒。
- 異步雙寫:先同步MySQL,再用MQ同步ES闽瓢。
- 優(yōu)點(diǎn):優(yōu)雅接癌,由于MQ(非Redis實(shí)現(xiàn)的MQ)具有高可用機(jī)制,因此ES消費(fèi)失敗可以重試扣讼。
- 缺點(diǎn):多了一個(gè)MQ缺猛,就多了一層運(yùn)維成本。有延遲。
- 自動(dòng)化任務(wù)荔燎,定時(shí)遍歷SQL:用時(shí)間戳做標(biāo)識(shí)符耻姥,用于區(qū)分哪些數(shù)據(jù)未同步,沒有同步就用腳本定時(shí)同步到ES有咨。
- 優(yōu)點(diǎn):業(yè)務(wù)邏輯層不需要額外的針對(duì)ES做寫操作琐簇。
- 缺點(diǎn):實(shí)時(shí)性不夠,對(duì)MySQL壓力大座享。
- 使用Canal基于Binlog進(jìn)行接近實(shí)時(shí)的同步,使用Canal監(jiān)聽MySQL Binlog婉商,并部署同步ES數(shù)據(jù)的腳本,從而自動(dòng)化保持同步征讲。也可直接利用Canal同步ES据某。相關(guān)鏈接:https://github.com/alibaba/canal/wiki/Sync-ES。
- 優(yōu)點(diǎn):實(shí)時(shí)性高诗箍,對(duì)業(yè)務(wù)層代碼無侵入癣籽。
- 缺點(diǎn):多了一個(gè)Canal,就多了一層運(yùn)維成本滤祖。
高并發(fā)下ES本身一致性解決方案
- 問題:與上文講的數(shù)據(jù)庫一致性筷狼,不是一個(gè)東西。這里講的是并發(fā)下ES本身更新數(shù)據(jù)導(dǎo)致的一致性問題匠童。例如并發(fā)過來的兩個(gè)請(qǐng)求埂材,查詢到結(jié)果是10,都想要-1汤求,等兩個(gè)執(zhí)行完畢后俏险,結(jié)果不是8而是9,那么就出現(xiàn)了數(shù)據(jù)一致性問題扬绪。
- ES之外的解決方案:分布式鎖竖独。或非分布式環(huán)境下編程語言自帶的具有排它性的鎖挤牛。
- ES樂觀鎖解決方案1:
背景:先創(chuàng)建一個(gè)num_test索引莹痢,并添加名為num的int類型的映射。并插入一條數(shù)據(jù)墓赴。
流程:當(dāng)進(jìn)行數(shù)據(jù)更新時(shí)竞膳,先做一次查詢(get方法,不是search方法)诫硕,獲取相關(guān)的_primary_term坦辟,_seq_no值。
當(dāng)更新數(shù)據(jù)時(shí)章办,添加對(duì)應(yīng)的版本號(hào)锉走,如果ES檢測(cè)到版本號(hào)不對(duì)滔吠,則會(huì)報(bào)錯(cuò),如下:
$params = [
'index' => 'num_test',
'id' => 1,
'body' => [
'doc' => [
'num' => 10
]
],
'if_seq_no' => 3, // 使用序列號(hào)
'if_primary_term' => 1, // 使用主分片術(shù)語
];
try {
$response = $client->update($params);
} catch (\Exception $exception) {
echo '出錯(cuò)了挠日,這里重試查詢后再更新,或者記錄錯(cuò)誤等其它操作翰舌。嚣潜。。'
}
- ES樂觀鎖解決方案2(不生效椅贱,請(qǐng)勿使用):
$params = [
'index' => 'num_test',
'id' => 1,
'body' => [
'doc' => [
'num' => 1800
]
],
'version' => 40, // 提供外部版本號(hào)
'version_type' => 'external' // 使用外部版本號(hào)
];
try {
$response = $client->update($params); //版本不生效的方案懂算,不推薦使用
} catch (\Exception $exception) {
dump('出錯(cuò)了,這里進(jìn)行重試庇麦,或者記錄錯(cuò)誤计技,等其它操作');
}
- ES應(yīng)對(duì)高并發(fā)寫的報(bào)錯(cuò)問題(和上文內(nèi)容不是一回事):ES針對(duì)大量的并發(fā)過來的寫請(qǐng)求,ES支持的并不好山橄,ES底層采用樂觀鎖的形式垮媒,這會(huì)導(dǎo)致ES內(nèi)部在頻繁并發(fā)寫入時(shí)內(nèi)部維護(hù)版本號(hào)沖突,也就是說更新前查詢出來的版本號(hào)航棱,比當(dāng)前實(shí)際的版本號(hào)兴汀(被其它并發(fā)過來的請(qǐng)求增加了版本號(hào)),那就會(huì)報(bào)錯(cuò)饮醇,這也就是所謂的ES報(bào)版本沖突的錯(cuò)誤的問題它抱,對(duì)于這種場(chǎng)景,可添加重試次數(shù)朴艰,和業(yè)務(wù)層的異常獲取作為兜底策略观蓄。重試代碼示例如下:
$params = [
'index' => 'index',
'id' => '10',
'body' => [
'doc' => [
'field1' => 'new value1',
'field2' => 'new value2'
]
],
'retry_on_conflict' => 3 // 設(shè)置重試次數(shù)
];
try {
$response = $client->update($params);
} catch (Exception $e) {
// 處理異常,可以選擇記錄日志或執(zhí)行其它操作祠墅,這個(gè)catch是用來重試3次還報(bào)錯(cuò)的兜底策略侮穿。
}
為什么不用ES替代MySQL
- ES沒有MySQL的事務(wù)機(jī)制,高可用無法保證饵隙。
- ES沒有MySQL的關(guān)系型側(cè)重撮珠,MySQL有強(qiáng)大的關(guān)聯(lián)策略,MySQL join多張表時(shí)金矛,ES需要手動(dòng)實(shí)現(xiàn)芯急。
- ES的定位是快速索引快速查找,并非有過多高可用存儲(chǔ)的機(jī)制驶俊,還是需要配合MySQL使用娶耍。
EQL
- 極簡(jiǎn)概括:Event Query Language用于在ES中進(jìn)行事件數(shù)據(jù)查詢的類SQL語言。
- 解決問題:為了更方便地分析時(shí)間序列數(shù)據(jù)和事件流數(shù)據(jù)饼酿,特別適用于安全事件榕酒、日志數(shù)據(jù)和監(jiān)控?cái)?shù)據(jù)的分析胚膊。
- 棄用原因:多用于快速調(diào)試。畢竟ES不是MySQL想鹰,SQL API 并不是ES中所有功能的完整替代品紊婉,有些復(fù)雜的查詢和功能可能需要使用原生的ES查詢 DSL(ES領(lǐng)域或問題域設(shè)計(jì)的編程語言或語法)。
- 簡(jiǎn)單示例:要查詢索引下的一條數(shù)據(jù)
POST IP:9200/_sql?format=json //類型可未txt辑舷,用制表符更直觀的展示
{
"query": "SELECT * FROM php_index WHERE city = '北京市'"
}
結(jié)果:
{
"columns": [
{
"name": "_boost",
"type": "float"
},
{
"name": "area",
"type": "integer"
},
{
"name": "city",
"type": "keyword"
},
{
"name": "description",
"type": "text"
},
{
"name": "id",
"type": "long"
},
{
"name": "population",
"type": "integer"
}
],
"rows": [
[
null,
16411,
"北京市",
"北京市(Beijing)喻犁,簡(jiǎn)稱“京”,古稱燕京何缓、北平肢础,是中華人民共和國首都、直轄市碌廓、國家中心城市传轰、超大城市, 國務(wù)院批復(fù)確定的中國政治中心谷婆、文化中心慨蛙、國際交往中心、科技創(chuàng)新中心纪挎, 中國歷史文化名城和古都之一股淡,世界一線城市",
1,
2186
]
]
}
- 演示2:查詢所有索引:
POST IP:9200/_sql?format=txt
{
"query": "show tables"
}
catalog | name | type | kind
---------------+--------------------------------------------------+---------------+---------------
zs_es_cluster |.alerts-default.alerts-default |VIEW |ALIAS
zs_es_cluster |.alerts-ml.anomaly-detection-health.alerts-default|VIEW |ALIAS
zs_es_cluster |.alerts-ml.anomaly-detection.alerts-default |VIEW |ALIAS
zs_es_cluster |.alerts-observability.apm.alerts-default |VIEW |ALIAS
zs_es_cluster |.alerts-observability.logs.alerts-default |VIEW |ALIAS
zs_es_cluster |.alerts-observability.metrics.alerts-default |VIEW |ALIAS
zs_es_cluster |.alerts-observability.slo.alerts-default |VIEW |ALIAS
zs_es_cluster |.alerts-observability.threshold.alerts-default |VIEW |ALIAS
zs_es_cluster |.alerts-observability.uptime.alerts-default |VIEW |ALIAS
zs_es_cluster |.alerts-security.alerts-default |VIEW |ALIAS
zs_es_cluster |.alerts-stack.alerts-default |VIEW |ALIAS
zs_es_cluster |.alerts-transform.health.alerts-default |VIEW |ALIAS
zs_es_cluster |.kibana-observability-ai-assistant-conversations |VIEW |ALIAS
zs_es_cluster |.kibana-observability-ai-assistant-kb |VIEW |ALIAS
zs_es_cluster |.siem-signals-default |VIEW |ALIAS
zs_es_cluster |my_index |TABLE |INDEX
zs_es_cluster |num_test |TABLE |INDEX
zs_es_cluster |php_index |TABLE |INDEX
zs_es_cluster |test_index |TABLE |INDEX
zs_es_cluster |zs_index |TABLE |INDEX