ElasticSearch第1講(4萬字詳解 Linux下安裝鱼的、原生調(diào)用、API調(diào)用超全總結(jié)痘煤、Painless凑阶、IK分詞器、4種和數(shù)據(jù)庫同步方案衷快、高并發(fā)下一致性解決方案宙橱、Kibana、 ELK)

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增刪改查

返回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)義字符仍舊生效(&nbsp;仍舊是空格)杨箭,且會(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)義字符仍舊生效(&nbsp;仍舊是空格),且會(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

保證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          

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市廷区,隨后出現(xiàn)的幾起案子唯灵,更是在濱河造成了極大的恐慌,老刑警劉巖隙轻,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件埠帕,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡玖绿,警方通過查閱死者的電腦和手機(jī)敛瓷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來斑匪,“玉大人呐籽,你說我怎么就攤上這事∈慈常” “怎么了狡蝶?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)贮勃。 經(jīng)常有香客問我贪惹,道長(zhǎng),這世上最難降的妖魔是什么寂嘉? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任奏瞬,我火速辦了婚禮枫绅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘硼端。我一直安慰自己并淋,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布珍昨。 她就那樣靜靜地躺著预伺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪曼尊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天脏嚷,我揣著相機(jī)與錄音骆撇,去河邊找鬼。 笑死父叙,一個(gè)胖子當(dāng)著我的面吹牛神郊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播趾唱,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼涌乳,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了甜癞?” 一聲冷哼從身側(cè)響起夕晓,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎悠咱,沒想到半個(gè)月后蒸辆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡析既,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年躬贡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片眼坏。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拂玻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宰译,到底是詐尸還是另有隱情檐蚜,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布沿侈,位于F島的核電站熬甚,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏肋坚。R本人自食惡果不足惜乡括,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一肃廓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧诲泌,春花似錦盲赊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至葵第,卻和暖如春绘迁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卒密。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國打工缀台, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人哮奇。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓膛腐,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親鼎俘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子哲身,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容