ElasticSearch第1讲(4万字详解 Linux下安装、原生调用、API调用超全总结、 ...

打印 上一主题 下一主题

主题 619|帖子 619|积分 1867

ElasticSearch


  • 官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/getting-started.html
  • 非官方中文文档:https://learnku.com/docs/elasticsearch73/7.3
  • 极简概括:基于Apache Lucene构建开源的分布式搜索引擎。
  • 解决题目:MySQL like中文全文搜索不走索引,或大数据搜索性能低下的题目。
  • 适用场景:

    • 大数据检索:在大数据量的查询场景下,ES查询性能依然保持上风,常用于替代MySQL由于性能不足而做一些复杂的查询。
    • 大数据开辟:大数据开辟几乎离不开Spark、Fink、Hadoop、ElasticSearch、MySQL、Redis、ZooKeeper这些组件。
    • ELK结合:ES结合LK作为ELK(Elasticsearch(搜索), Logstash(采集转换), Kibana(分析))组合,可用于及时监控、分析和可视化大量日记和事件数据,如系统日记、应用程序日记、网络流量日记等。

  • 优点:

    • 跨平台:组件支持在Linux、Windows、MacOS上运行。
    • 查询性能优异:在超大数据量的查询场景下,ES查询性能依然保持上风。
    • 支持全文检索:替代MySQL中文全文检索不走索引的查询弱项。
    • 生态繁荣:是面向开辟者的主流的搜索引擎,文档,解决方案,疑难杂症,非0day毛病,基本都有成熟的解决方案。
    • 支持分布式:每个ES节点,都可以执行一部门搜索任务,然后将结果合并。累加的算力结果为虎傅翼。
    • 支持复杂查询:支持,模糊匹配,范围查询,布尔搜索。

  • 缺点:

    • ES没有事务机制,对于MySQL的合作呢,也是最终一致性,以是强一致性的搜索环境下并不适用,保举Redis。
    • json请求体父子格式反人类:果然技能厉害的程序员往往不会是一个好的产品司理。
    • json响应体格式反人类,按照["成功或失败的code", "data数据", "msg增补说明"]这种格式返回就好了。
    • PHP API经常性异常:APi接口,写操作失败返回false也行,非要返回异常,异常若没有处理,会中断程序执行。
    • 查询方式受mapping限制:相比于MySQL,哪怕是个数字,都可以用like强制查询,但是ES不行。

  • 同类组件:Apache Solr、Apache Lucene、Algolia、Sphinx、XunSearch。
正排索引和倒排索引

ES用的倒排索引算法。正倒两种索引都是用于快速检索数据的实现方案,我没有太官方的解释,以是举例说明:

  • 正排索引:有一个文章表,有文章id、标题、详情3个字段,通过文章列表功能获取文章,通过id作为索引值获取文章内容,这是很广泛的业务逻辑。想要搜索包含指定关键词的文章,数据库就必要对文章的标题和内容逐一做对比,因为不走索引,数据量不大还好,数据量一大性能降低。
  • 倒排索引:用于加快文本的检索,文章内容利用分词器拆分,将拆分好的关键词与文章id做关联,然后生存。类比MySQL表的两个列,一列是关键词,另一列是包含这个关键词的文章id,多个倒排索引数据集构成一个倒排表。再查询时,不必要针对数据源本身做查询,而是变成了,关键词为xxx的id为多少。
分词

分词就是把字符串拆分成有效的关键词,用于提供高质量搜索的数据源。

  • 对英文:分词直接用空格就行,I love you,可直接利用空格分成3个词,对中文显然不适用。
  • 对中文:例如“本日温度很高”,能用的词汇可以拆分成“本日”、“温度”、“很高”,可程序不知道怎么拆分,若拆分为“本日温”、“天温”、“”度很”这样的关键词就显得很怪异。
    以是也就诞生了语法分析+字典的解决方案,用人工干涉+词典的方式实现分词器的逻辑。
    至于利用NLP语义分析,上下文猜测,的AI模式,不属于ES的范畴,不展开。
  • 若搜索关键词为语句或短语:必要利用TF-IDF和BM25算法(等更高级的算法),先对句子进行分词,然后根据这多个分词的再对结果集进行分词查询,然后评分,组合,最终返回结果。
安装ES 8.14.1


  • 系统设置,用于开启防火墙,创建用户,和大数据环境下提升性能。
  1. Java写的组件吃内存,建议VM虚拟机内存设置大一点,系统设置为1G内存。
  2. 开两个端口,并重启防火墙
  3. firewall-cmd --add-port=9200/tcp --zone=public --permanent
  4. firewall-cmd --add-port=9300/tcp --zone=public --permanent
  5. systemctl restart firewalld
  6. 新建一个es用户,以非root形式运行,否则运行es会报错,java.lang.RuntimeException: can not run elasticsearch as root
  7. useradd -M es
  8. passwd es 密码为123456
  9. vim  /etc/security/limits.conf
  10. 文末添加两行配置,优化文件描述符软硬限制,对提高性能非常重要,文件描述符用于标识和管理每个进程都可以打开文件的数量
  11. es soft nofile 65536
  12. es hard nofile 65536
  13. vim /etc/security/limits.d/20-nproc.conf
  14. 文末添加两行配置,优化文件描述符软硬限制,对提高性能非常重要,文件描述符用于标识和管理每个进程都可以打开文件的数量
  15. es soft nofile 65536
  16. es hard nofile 65536
  17. vim /etc/sysctl.conf
  18. 定义系统中可以同时打开的最大文件描述符数量。
  19. fs.file-max=655350
  20. 定义Linux内核中进程可以拥有的最大内存映射区域数量
  21. vm.max_map_count=262144
  22. 重启
  23. sysctl -p
复制代码

  • 安装相关
  1. 下载tar包并解压,这个包地址来源于官网,并非java源码包
  2. wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.14.1-linux-x86_64.tar.gz
  3. tar zxf elasticsearch-8.14.1-linux-x86_64.tar.gz
  4. 更改所属的用户和用户组
  5. chown -R es:es elasticsearch-8.14.1
  6. 切换用户
  7. su es
  8. 启动ES,如果发现报错,请清空bin目录同级的data目录
  9. ./bin/elasticsearch
  10. 启动后,直到看到如下字样,说明能成功启动,但是输入它生成的用户名密码,登不进去
  11. 然后Ctrl + C强制停止,因为启动一次之后,config/elasticsearch.yml配置文件,会发生变化,这一步不可少
  12. Elasticsearch security features have been automatically configured!
  13. 登不进去,那就改配置
  14. vim config/elasticsearch.yml
  15. 把91~103行的true全部改为false,如下,注意配置格式,key: value之间要留出空格,否则ES不识别对应的值。
  16. # Enable security features
  17. xpack.security.enabled: false
  18. xpack.security.enrollment.enabled: false
  19. # Enable encryption for HTTP API client connections, such as Kibana, Logstash, and Agents
  20. xpack.security.http.ssl:
  21.   enabled: false
  22.   keystore.path: certs/http.p12
  23. # Enable encryption and mutual authentication between cluster nodes
  24. xpack.security.transport.ssl:
  25.   enabled: false
  26. 保存退出后,清除初始化的data数据
  27. rm -rf elasticsearch-8.14.1/data/*
  28. 再次执行,并使其后台运行
  29. ./bin/elasticsearch -d
  30. 查看进程,确定ES是否成功执行
  31. ps aux | grep elastic
  32. 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
  33. 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
  34. es        49230  0.0  0.0 112828   968 pts/0    R+   05:10   0:00 grep elastic
  35. 访问:
  36. http://IP:9200/
复制代码
设置密码(保举添加)

上文设置的是没有密码的方案,倘若服务器IP和端口对外暴露,这不是一种安全的行为。
注意,要部署集群,各个节点密码应当一致。
  1. 注意配置格式,key: value之间要留出空格,否则ES不识别对应的值。
  2. vim es根目录/config/elasticsearch.yml
  3. 修改以下配置
  4. xpack.security.enabled: true
  5. 非root用户下启动es
  6. ./bin/elasticsearch -d
  7. 启动一个交互式命令行界面,从而设置密码,期间的几个交互,全部设置为123456
  8. ./bin/elasticsearch-setup-passwords interactive
  9. 默认用户名:elastic
  10. 密码:123456
复制代码
概念辅助类比

ES中有些新的概念,可通过MySQL的概念去辅助记忆。
ESMySQL备注Index(索引)库表/Type(类型)表7及以上的版本被移除,原先是对标MySQL表的理念,厥后发现这对于ES并非必须,就移除了Documents(文档)行数据/Fields(字段)字段/Mapping(映射)表结构/Shards(分片)分表顾名思义,当数据量太大单个节点都装不下的时候,就拆分到别的节点上默认页说明


  • 默认页:
    GET请求IP:9200/
  1. {
  2.     "name": "lnmp",
  3.     "cluster_name": "elasticsearch",
  4.     "cluster_uuid": "k61PBMDqTKO31rZeV-ENGA",
  5.     "version": {
  6.         "number": "8.14.1",
  7.         "build_flavor": "default",
  8.         "build_type": "tar",
  9.         "build_hash": "93a57a1a76f556d8aee6a90d1a95b06187501310",
  10.         "build_date": "2024-06-10T23:35:17.114581191Z",
  11.         "build_snapshot": false,
  12.         "lucene_version": "9.10.0",
  13.         "minimum_wire_compatibility_version": "7.17.0",
  14.         "minimum_index_compatibility_version": "7.0.0"
  15.     },
  16.     "tagline": "You Know, for Search"
  17. }
  18. "name": "lnmp":系统标识
  19. "cluster_name": "elasticsearch":Elasticsearch 集群的名称为 “elasticsearch”。
  20. "cluster_uuid": "k61PBMDqTKO31rZeV-ENGA":Elasticsearch集群的唯一标识符。
  21. "version":版本信息:
  22. "number": 版本号
  23. "build_flavor": "default":构建的类型,这里是默认的。
  24. "build_type": "tar":构建类型为 tar 包。
  25. "build_hash": "93a57a1a76f556d8aee6a90d1a95b06187501310":构建的哈希值,用于唯一标识这个特定的构建。
  26. "build_date": "2024-06-10T23:35:17.114581191Z":构建的日期和时间。
  27. "build_snapshot": false:表示这个构建不是一个快照版本。
  28. "lucene_version": "9.10.0":基于Lucene 9.10.0的版本。
  29. "minimum_wire_compatibility_version": "7.17.0":最低兼容的网络传输版本。
  30. "minimum_index_compatibility_version": "7.0.0":最低兼容的索引版本。
  31. "tagline": "You Know, for Search":Elasticsearch 的标语,说明其用途是进行搜索。
复制代码
索引增删查操作


  • 创建索引:
    PUT请求 IP:9200/索引名
  1. {
  2.         "acknowledged": true,
  3.         "shards_acknowledged": true,
  4.         "index": "zs_index"
  5. }
  6. "acknowledged": true:指示请求是否被成功接受和处理。
  7. "shards_acknowledged": true:指示所有分片是否已经确认请求。
  8. "index": "zs_index":这表示操作涉及的索引名称为 “zs_index”。
复制代码

  • 创建索引:
    重复创建,报错说明:
  1. {
  2.         "error": {
  3.                 "root_cause": [
  4.                         {
  5.                                 "type": "resource_already_exists_exception",
  6.                                 "reason": "index [zs_index/dCMAgdlqTeaihB4JSH1gNw] already exists",
  7.                                 "index_uuid": "dCMAgdlqTeaihB4JSH1gNw",
  8.                                 "index": "zs_index"
  9.                         }
  10.                 ],
  11.                 "type": "resource_already_exists_exception",
  12.                 "reason": "index [zs_index/dCMAgdlqTeaihB4JSH1gNw] already exists",
  13.                 "index_uuid": "dCMAgdlqTeaihB4JSH1gNw",
  14.                 "index": "zs_index"
  15.         },
  16.         "status": 400
  17. }
  18. "error":这个对象包含了发生的错误信息。
  19. "root_cause":根本原因的数组,指示导致问题的具体原因。
  20. "type": "resource_already_exists_exception":错误的类型,表示尝试创建的索引已经存在。
  21. "reason": "index [zs_index/dCMAgdlqTeaihB4JSH1gNw] already exists":错误的详细原因,指明索引 “zs_index” 和其唯一标识符 “dCMAgdlqTeaihB4JSH1gNw” 已经存在。
  22. "index_uuid": "dCMAgdlqTeaihB4JSH1gNw":已存在索引的 UUID。
  23. "index": "zs_index":已存在索引的名称。
  24. "type": "resource_already_exists_exception":总体错误类型,与根本原因相同。
  25. "reason": "index [zs_index/dCMAgdlqTeaihB4JSH1gNw] already exists":再次指明索引已经存在的原因。
  26. "index_uuid": "dCMAgdlqTeaihB4JSH1gNw":重复指定已存在索引的 UUID。
  27. "index": "zs_index":重复指定已存在索引的名称。
  28. "status": 400:HTTP 状态码,表示客户端请求错误
复制代码

  • 检察索引:
    GET请求 IP:9200/索引名
  1. {
  2.         "zs_index": {
  3.                 "aliases": {},
  4.                 "mappings": {},
  5.                 "settings": {
  6.                         "index": {
  7.                                 "routing": {
  8.                                         "allocation": {
  9.                                                 "include": {
  10.                                                         "_tier_preference": "data_content"
  11.                                                 }
  12.                                         }
  13.                                 },
  14.                                 "number_of_shards": "1",
  15.                                 "provided_name": "zs_index",
  16.                                 "creation_date": "1719699272706",
  17.                                 "number_of_replicas": "1",
  18.                                 "uuid": "dCMAgdlqTeaihB4JSH1gNw",
  19.                                 "version": {
  20.                                         "created": "8505000"
  21.                                 }
  22.                         }
  23.                 }
  24.         }
  25. }
  26. "aliases": {}:索引的别名列表为空,表示该索引当前没有别名。
  27. "mappings": {}:索引的映射为空对象,即没有定义特定的字段映射。
  28. "settings":索引的设置信息:
  29. "index":
  30. "routing":
  31. "allocation":
  32. "include":
  33. "_tier_preference": "data_content":指定索引分配时偏好的数据内容层级。
  34. "number_of_shards": "1":该索引被分成了一个分片。
  35. "provided_name": "zs_index":索引的提供的名称为 “zs_index”。
  36. "creation_date": "1719699272706":索引的创建日期的时间戳形式。
  37. "number_of_replicas": "1":该索引有一个副本。
  38. "uuid": "dCMAgdlqTeaihB4JSH1gNw":索引的唯一标识符 UUID。
  39. "version":
  40. "created": "8505000":索引的版本信息,表示索引在 Elasticsearch 版本 “8505000” 中创建。
复制代码

  • 检察所有索引:
    GET请求 IP:9200/_cat/indices?v
  1. health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size dataset.size
  2. yellow open   zs_index dCMAgdlqTeaihB4JSH1gNw   1   1          0            0       249b           249b         249b
  3. health: 索引的健康状态,此处为 “yellow”,表示所有预期的分片都可用,但副本尚未分配。
  4. status: Elasticsearch 的状态指示符,这里是 “open”,表示索引是打开状态,可以接收读写操作。
  5. index: 索引名。
  6. uuid: 索引的唯一标识符。
  7. pri: 主分片数为 1,即索引被分成了一个主分片。
  8. rep: 副本数为 1,表示每个主分片有一个副本。
  9. docs.count: 文档数量为 0,当前索引中的文档总数。
  10. docs.deleted: 已删除的文档数量为 0。
  11. store.size: 存储大小为 249b,索引占用的物理存储空间。
  12. pri.store.size: 主分片的存储大小,也是 249b。
  13. dataset.size: 数据集大小为 249b,即索引的数据集大小。
复制代码

  • 删除索引 DELETE方式 IP:9200/索引名
  1. {
  2.         "acknowledged": true
  3. }
  4. 返回true表示成功执行。
复制代码
文档增编削查操作


  • 增文档(数据):
    方式1:POST请求 IP:9200/索引名/_doc/可选参数,数据唯一标识
    方式2:PUT请求 IP:9200/索引名/_create/必填唯一标识符 由于方式2的put请求是幂等,以是再次请求会报错
  1. 这是存入的数据
  2. {
  3.     "id":1,
  4.     "content":"C是世界上最好的编程语言"
  5. }
  6. 这是返回的数据,若用户指定id,则id处显示的是用户指定的id
  7. {
  8.         "_index": "zs_index",
  9.         "_id": "0mMsZpABZdTHCHXLZQhu",
  10.         "_version": 1,
  11.         "result": "created",
  12.         "_shards": {
  13.                 "total": 2,
  14.                 "successful": 1,
  15.                 "failed": 0
  16.         },
  17.         "_seq_no": 0,
  18.         "_primary_term": 1
  19. }
  20. "_index": "zs_index": 表示文档被添加到了名为zs_index的索引中。
  21. "_id": "0mMsZpABZdTHCHXLZQhu": 是新添加的文档的ID。在Elasticsearch中,每个文档都有一个唯一的ID,用于唯一标识和检索该文档。
  22. "_version": 1: 表示该文档的版本号是1。每当文档被更新时,版本号会增加,这有助于跟踪文档的更改历史。
  23. "result": "created": 表示操作的结果是创建了一个新的文档。
  24. "_shards": 这个字段提供了关于索引操作的分片信息。
  25. "total": 2: 表示总共有2个分片参与了这次索引操作(通常是一个主分片和其副本)。
  26. "successful": 1: 表示有1个分片成功完成了索引操作。在yellow健康状态的索引中,这通常意味着主分片成功了,但副本分片可能还没有数据(因为它是yellow状态,副本可能还没有分配或同步)。
  27. "failed": 0: 表示没有分片失败。
  28. "_seq_no": 0: 是文档在Lucene段中的序列号,用于在内部跟踪文档的版本和顺序。
  29. "_primary_term": 1: 主要术语(primary term)是与_seq_no一起使用的,用于确保文档版本的一致性,特别是在主节点更换时。
复制代码

  • 改文档(数据):
    方式1(用于覆盖老数据):POST请求 IP:9200/索引名/_doc/唯一标识
    方式2(用于覆盖老数据):PUT请求 IP:9200/索引名/_doc/唯一标识
    方式3(用于修改局部数据):POST请求  IP:9200/索引名/_update/唯一标识
  1. 方式1,若有id号,再次执行增文档操作,可自动将create操作编程update操作。
  2. 更新数据
  3. {
  4.     "id":1,
  5.     "content":"C是世界上最好的编程语言"
  6. }
  7. 方式2,请求内容同方式1
  8. 方式3,因为要修改局部数据,所以必须告知ES修改那块的局部数据,以下:第一层花括号和doc是固定格式。
  9. {
  10.     "doc" : {
  11.         "content": "C是最好的编程语言"
  12.     }
  13. }
  14. 3种方式的响应格式一致:
  15. {
  16.         "_index": "zs_index",
  17.         "_id": "1",
  18.         "_version": 17,
  19.         "result": "updated",
  20.         "_shards": {
  21.                 "total": 2,
  22.                 "successful": 1,
  23.                 "failed": 0
  24.         },
  25.         "_seq_no": 24,
  26.         "_primary_term": 1
  27. }
  28. "_index": "zs_index": 表示被更新的文档位于名为zs_index的索引中。
  29. "_id": "1": 是被更新的文档的唯一ID。
  30. "_version": 17: 表示该文档的版本号已更新为17。版本号在每次更新时增加,用于跟踪文档的变化历史。
  31. "result": "updated": 表示更新操作已成功执行,文档被更新了。
  32. "_shards": 提供了关于更新操作涉及的分片信息。
  33. "total": 2: 表示总共有2个分片参与了更新操作(通常是一个主分片和其副本)。
  34. "successful": 1: 表示有1个分片成功完成了更新操作。在yellow健康状态的索引中,这意味着主分片成功了,但副本分片可能尚未同步数据。
  35. "failed": 0: 表示没有分片失败。
  36. "_seq_no": 24: 是文档在Lucene段中的序列号,用于内部跟踪文档版本和顺序。
  37. "_primary_term": 1: 主要术语(primary term)与_seq_no一起使用,确保文档版本的一致性,特别是在主节点更换时。
复制代码

  • 查询单条数据:
    GET请求 IP:9200/索引名/_doc/唯一标识
  1. {
  2.         "_index": "zs_index",
  3.         "_id": "1",
  4.         "_version": 8,
  5.         "_seq_no": 14,
  6.         "_primary_term": 1,
  7.         "found": true,
  8.         "_source": {
  9.                 "id": 1,
  10.                 "content": "C是世界上最好的编程语言"
  11.         }
  12. }
  13. "_seq_no": 14: 是文档在Lucene段中的序列号,用于内部跟踪文档版本和顺序。
  14. "_primary_term": 1: 主要术语(primary term)与_seq_no一起使用,确保文档版本的一致性,尤其是在主节点更换时。
  15. "found": true: 表示Elasticsearch成功找到了指定ID的文档,若为false,表示未找到。
  16. "_source": 包含了文档的实际内容。
复制代码

  • 查询多条数据:
    GET请求 IP:9200/索引名/_search
  1. {
  2.         "took": 137,
  3.         "timed_out": false,
  4.         "_shards": {
  5.                 "total": 1,
  6.                 "successful": 1,
  7.                 "skipped": 0,
  8.                 "failed": 0
  9.         },
  10.         "hits": {
  11.                 "total": {
  12.                         "value": 8,
  13.                         "relation": "eq"
  14.                 },
  15.                 "max_score": 1,
  16.                 "hits": [
  17.                         {
  18.                                 "_index": "zs_index",
  19.                                 "_id": "1",
  20.                                 "_score": 1,
  21.                                 "_source": {
  22.                                         "id": 1,
  23.                                         "content": "C是世界上最好的编程语言"
  24.                                 }
  25.                         },
  26.                         {
  27.                                 "_index": "zs_index",
  28.                                 "_id": "02M0ZpABZdTHCHXLjAgN",
  29.                                 "_score": 1,
  30.                                 "_source": {
  31.                                         "id": 1,
  32.                                         "content": "C是世界上最好的编程语言"
  33.                                 }
  34.                         }
  35.                 ]
  36.         }
  37. }
  38. "took": 137: 表示搜索操作耗费了137毫秒。
  39. "timed_out": false: 表示搜索操作未超时。
  40. "_shards": 提供了关于搜索操作涉及的分片信息。
  41. "total": 1: 表示总共有1个分片参与了搜索操作。
  42. "successful": 1: 表示所有参与的分片都成功完成了搜索。
  43. "skipped": 0: 表示没有分片被跳过。
  44. "failed": 0: 表示没有分片失败。
  45. "hits": 包含了搜索结果的详细信息。
  46. "total": {"value": 8, "relation": "eq"}: 表示符合搜索条件的文档总数为8个。
  47. "value": 8: 具体的文档数。
  48. "relation": "eq": 表示与总数值相等,即已经获取了所有匹配的文档。
  49. "hits"数组: 包含了每个匹配文档的详细信息。
  50. 每个文档对象包括了:
  51. "_index": "zs_index": 文档所属的索引名称。
  52. "_id": 文档的唯一ID。
  53. "_score": 1: 文档的匹配分数,此处为1(最高分)。
  54. "_source": 包含了文档的实际内容。
复制代码

  • 删除数据
    DELETE请求 IP:9200/索引名/_doc/唯一标识
  1. {
  2.         "_index": "zs_index",
  3.         "_id": "1",
  4.         "_version": 24,
  5.         "result": "not_found",
  6.         "_shards": {
  7.                 "total": 2,
  8.                 "successful": 1,
  9.                 "failed": 0
  10.         },
  11.         "_seq_no": 31,
  12.         "_primary_term": 1
  13. }
  14. "result": "not_found": 表示更新操作未找到指定的文档,若是deleted,表示成功删除。
  15. _shards": 提供了关于更新操作涉及的分片信息。
  16. "total": 2: 表示总共有 2 个分片参与了更新操作(通常是一个主分片和其副本)。
  17. "successful": 1: 表示有 1 个分片成功完成了更新操作。在索引状态为 yellow 时,这可能意味着主分片成功了,但副本分片可能尚未同步数据。
  18. "failed": 0: 表示没有分片失败。
  19. "_seq_no": 31: 是文档在 Lucene 段中的序列号,用于内部跟踪文档版本和顺序。
  20. "_primary_term": 1: 主要术语(primary term)与 _seq_no 一起使用,确保文档版本的一致性,特别是在主节点更换时。
复制代码
文档复杂查询操作


  • 通过关键词查询:
    方式1:GET请求 IP:9200/索引名/_search?q=文档字段名:要搜索的关键字
    方式2:GET请求 IP:9200/索引名/_search
    并添加请求body{   "query":{       "match": {           "文档字段名":"要搜索的关键字"       }   } }
  1. {
  2.         "took": 8,
  3.         "timed_out": false,
  4.         "_shards": {
  5.                 "total": 1,
  6.                 "successful": 1,
  7.                 "skipped": 0,
  8.                 "failed": 0
  9.         },
  10.         "hits": {
  11.                 "total": {
  12.                         "value": 6,
  13.                         "relation": "eq"
  14.                 },
  15.                 "max_score": 0.074107975,
  16.                 "hits": [
  17.                         {
  18.                                 "_index": "zs_index",
  19.                                 "_id": "0mMsZpABZdTHCHXLZQhu",
  20.                                 "_score": 0.074107975,
  21.                                 "_source": {
  22.                                         "id": 1,
  23.                                         "content": "C是世界上最好的编程语言"
  24.                                 }
  25.                         }
  26.                 ]
  27.         }
  28. }
  29. took: 查询花费的时间,单位为毫秒。在这个例子中,值为8,表示查询执行花费了8毫秒时间。
  30. timed_out: 表示查询是否超时。在这个例子中,值为false,表示查询未超时。
  31. _shards: 分片相关信息,包括:
  32. total: 总分片数,这里是1个分片。
  33. successful: 成功的分片数,这里是1个分片。
  34. skipped: 被跳过的分片数,这里是0个分片。
  35. failed: 失败的分片数,这里是0个分片。
  36. hits: 查询命中的结果集信息,包含:
  37. total: 总命中数,这里是6。
  38. max_score: 结果集中最高得分,这里是0.074107975。
  39. hits: 包含具体的命中文档数组。
  40. 每个文档包含以下信息:
  41. _index: 文档所在的索引。
  42. _id: 文档的唯一标识符。
  43. _score: 文档的得分。
  44. _source: 存储实际数据的字段。
复制代码

  • 分页查询:
    GET请求 IP:9200/索引名/_search
    body体添加{   "query": {           "match": {                   "文档字段名":"要搜索的关键字"           }   },   "from":0,   "size":2 }
    其中,from为起始位置偏移量,size为每页表现的条数。
    from算法:(页码 -1)* size = form。
    第1页:(1 - 1)*  2 = 0,以是from为0。
    第2页:(2 - 1)* 2 = 2,以是from为2。
    响应结果同上。
  • 只表现数据的部门字段:
    GET请求 IP:9200/索引名/_search
    body体添加_source项即可{   "query": {           "match": {                   "文档字段名":"要搜索的关键字"           }   },   "_source":["id"] }
    响应结果同上。
  • 排序:
    GET请求 IP:9200/索引名/_search
    body体添加sort项即可 {   "query": {           "match": {                   "文档字段名":"要搜索的关键字"           }   },   "sort":{       "排序的字段名":{           "order":"asc"       }   } }
    注意,这个将要排序的字段,可以不被展示出来也能排序(_source控制项)
    响应结果同上。
  • 多条件and或or查询,区间查询
    GET请求 IP:9200/索引名/_search
    如下,需添加以下body,表示查询content字段为C语言和(&&)C++语言(C++语言会被拆分),并且content>1(随意测试)的数据。
    若替换must为should,则表示或(or)之意。
  1. {
  2.         "query": {
  3.                 "bool": {
  4.                         "must": [
  5.                                 {
  6.                                         "match": {
  7.                                                 "content": "C语言"
  8.                                         }
  9.                                 },
  10.                                 {
  11.                                         "match": {
  12.                                                 "content": "C++语言"
  13.                                         }
  14.                                 }
  15.                         ],
  16.                         "filter": {
  17.                                 "range": {
  18.                                         "content": {
  19.                                                 "gt": 1
  20.                                         }
  21.                                 }
  22.                         }
  23.                 }
  24.         }
  25. }
复制代码
响应结果同上。

  • 全文精准匹配
    GET请求 IP:9200/索引名/_search
    仍需添加如下body{   "query":{       "match_phrase" :{           "字段名":"要搜索的关键字"       }   } }
    响应结果同上。
  • 查询到的结果高亮表现
    GET请求 IP:9200/索引名/_search
    仍需添加如下body{   "query":{       "match_phrase" :{          "字段名":"要搜索的关键字"       }   },   "highlight":{       "fields":{           "字段名":{}       }   } }
    响应结果同上。
聚合查询


  • 求指定字段均匀值
    由于聚合函数过多,逐一说明会让篇幅变的很长,因此保举看官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics.html
    GET请求 IP:9200/索引名/_search
    仍需添加如下body{   "aggs" : {       "id_group_avg" : {           "avg" : {               "field" : "字段名"           }       }   },   "size":0 }
    其中,id_group_avg为自定义名称,size:0表示去掉对文档数据的返回。
  1. {
  2.         "took": 35,
  3.         "timed_out": false,
  4.         "_shards": {
  5.                 "total": 1,
  6.                 "successful": 1,
  7.                 "skipped": 0,
  8.                 "failed": 0
  9.         },
  10.         "hits": {
  11.                 "total": {
  12.                         "value": 6,
  13.                         "relation": "eq"
  14.                 },
  15.                 "max_score": null,
  16.                 "hits": []
  17.         },
  18.         "aggregations": {
  19.                 "id_group_avg": {
  20.                         "value": 1
  21.                 }
  22.         }
  23. }
  24. took: 查询花费的时间,单位是毫秒。这里是 35 毫秒。
  25. timed_out: 查询是否超时。这里显示为 false,表示查询在规定时间内完成。
  26. _shards: 这个对象提供关于查询在分片上的执行情况的详细信息:
  27. total: 总分片数。
  28. successful: 成功完成查询的分片数。
  29. skipped: 跳过的分片数。
  30. failed: 查询失败的分片数。
  31. 在这个例子中,总分片数为 1,且成功完成了查询。
  32. hits: 包含有关查询匹配的文档信息:
  33. total: 文档匹配的总数。
  34. value: 匹配的文档数,这里是 6。
  35. relation: 匹配关系,这里是 “eq” 表示精确匹配。
  36. max_score: 最高得分,如果不需要计算得分则为 null。
  37. hits: 实际匹配的文档数组。在这个例子中是空的,因为没有具体的文档数据。
  38. aggregations: 聚合结果信息:
  39. id_group_avg: 聚合名称,这里的值为 1。具体的聚合结果会根据你的查询和聚合定义而有所不同。
复制代码
分词与不分词的控制

这块由于涉及到字段的改动,以是必要重新建立索引,并且添加了映射(mapping)的概念
  1. 重新建立一个people索引
  2. PUT请求 IP:9200/people
  3. 再次请求,添加映射
  4. IP:9200/people/_mapping
  5. {
  6.     "properties" :{
  7.         "name" : {
  8.             "type":"text",
  9.             "index":true
  10.         },
  11.         "sex" : {
  12.             "type":"keyword",
  13.             "index":true
  14.         },
  15.         "tel" : {
  16.             "type":"keyword",
  17.             "index":false
  18.         }
  19.     }
  20. }
  21. 上方的index指的是是否为这条数据添加索引。
  22. type是索引类型,text代表支持分词查询(MySQL like '%kw%'),keyword代表不可分词查询 (MySQL = 'kw')。
  23. 然后添加三条数据
  24. PUT IP:9200/people/_create/1
  25. {
  26.     "name":"张三",
  27.     "sex":"男性",
  28.     "tel":"18888888888"
  29. }
  30. PUT IP:9200/people/_create/2
  31. {
  32.     "name":"李四",
  33.     "sex":"女性",
  34.     "tel":"16666666666"
  35. }
  36. PUT IP:9200/people/_create/3
  37. {
  38.     "name":"王五",
  39.     "sex":"男性",
  40.     "tel":"18866668888"
  41. }
  42. 搜索
  43. GET IP:9200/people/_search
  44. {
  45.     "query" :{
  46.         "match" :{
  47.             "sex" : "男" 把性去掉,搜索不到数据
  48.         }
  49.     }
  50. }
  51. GET IP:9200/people/_search
  52. {
  53.     "query" :{
  54.         "match" :{
  55.             "name" : "张" 把三去掉,可以搜索到数据
  56.         }
  57.     }
  58. }
  59. GET IP:9200/people/_search
  60. {
  61.     "query" :{
  62.         "match" :{
  63.             "tel" : "188" 若输入手机号前3位,则搜不到数据,输入完整的手机号,则可以搜索到数据
  64.         }
  65.     }
  66. }
复制代码
PHP Api调用

官方文档:https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/getting-started-php.html#_installation
某些ES Api(例如创建索引)不能重复执行,重复执行会报错,以是在执行写操作的上游做判断,大概使用try catch。
  1. composer require elasticsearch/elasticsearch
  2. 推荐安装symfony/var-dumper,用于dd()或dump()执行,美化输出。
  3. 新建PHP文件,以下代码数据为公共部分。
  4. include './vendor/autoload.php';
  5. use Elastic\Elasticsearch\ClientBuilder;
  6. //连接ES
  7. $client = ClientBuilder::create()->setHosts(['192.168.0.183:9200'])->build();
  8. //若es有密码,则需要添加一个setBasicAuthentication()方法。
  9. $client = ClientBuilder::create()->setHosts(['192.168.0.183:9200'])->setBasicAuthentication('elastic', '123456')->build();
复制代码
PHP ES Api针对Index增编削查


  • 创建
  1. 返回bool
  2. $response = $client->indices()->create([
  3.     'index' => 'php_index'
  4. ]);
  5. $response->asBool();
复制代码

  • 查询 判断索引是否存在
  1. 返回bool
  2. $response = $client->indices()->exists(['index' => 'php_index']);
  3. dd($response->asBool());
复制代码

  • 查询 检察索引相关信息
  1. 返回array
  2. $response = $client->indices()->get(['index' => 'php_index']);
  3. dd($response->asArray());
复制代码

  • 删除
  1. 返回bool
  2. $response = $client->indices()->delete(['index' => 'php_index']);
  3. dd($response->asBool());
复制代码

  • 修改
    索引作为基础性的数据支撑,一般不做改动。
PHP ES  Api针对Mapping增编削查

  1. 返回bool
  2. $params = [
  3.     'index' => 'php_index',
  4.     'body' => [
  5.         'properties' => [
  6.             'name' => [
  7.                 'type' => 'text',
  8.             ],
  9.         ]
  10.     ]
  11. ];
  12. $response = $client->indices()->putMapping($params);
  13. dd($response->asBool());
复制代码

  • 增 创建索引时
  1. 返回bool
  2. $params = [
  3.     'index' => 'php_index',
  4.     'body' => [
  5.         'mappings' => [
  6.             'properties' => [
  7.                 'title' => [
  8.                     'type' => 'text',
  9.                 ],
  10.                 'content' => [
  11.                     'type' => 'text',
  12.                 ],
  13.             ]
  14.         ]
  15.     ]
  16. ];
  17. $response = $client->indices()->create($params);
  18. dd($response->asBool());
复制代码

  • 查 所有索引
  1. 返回数组
  2. $response = $client->indices()->getMapping();
  3. dd($response->asArray());
复制代码

  • 查 指定索引
  1. 返回数组
  2. $response = $client->indices()->getMapping(['index' => 'php_index']);
  3. dd($response->asArray());
复制代码


  • 请直接删除索引。

  • 请重新建立索引,在新索引基础上做映射的修改。
PHP ES  Api针对Doc增编削


  • 索引与映射如下:
  1. 准备四个直辖市的名称,简介,人口和面积大小。
  2. $params = [
  3.     'index' => 'php_index',
  4.     'body' => [
  5.         'mappings' => [
  6.             'properties' => [
  7.                 'city' => [
  8.                     'type' => 'keyword',
  9.                 ],
  10.                 'description' => [
  11.                     'type' => 'text',
  12.                 ],
  13.                 'population' => [
  14.                     'type' => 'integer'
  15.                 ],
  16.                 'area' => [
  17.                     'type' => 'integer'
  18.                 ],
  19.             ]
  20.         ]
  21.     ]
  22. ];
  23. $response = $client->indices()->create($params);
  24. dd($response->asArray());
复制代码

  • 增 单条 请记忆这4个直辖市的数据生存格式,下文基本每个演示都要用
    一级数组下有个id属性,若省去,ES会默认给这条数据加一个id。不保举。保举使用MySQL的数据id作为ES的id。
  1. 返回bool
  2. $params = [
  3.     'index' => 'php_index',
  4.     'id'   => 1,
  5.     'body' => [
  6.         'id'          => 1,
  7.         'city'        => '北京市',
  8.         'description' => '北京市(Beijing),简称“京”,古称燕京、北平,是中华人民共和国首都、直辖市、国家中心城市、超大城市, 国务院批复确定的中国政治中心、文化中心、国际交往中心、科技创新中心, 中国历史文化名城和古都之一,世界一线城市',
  9.         'population'  => '2186',
  10.         'area'        => '16411',
  11.     ]
  12. ];
  13. $response = $client->index($params);
  14. dd($response->asBool());
  15. 再增加3条数据
  16. $params = [
  17.     'index' => 'php_index',
  18.     'id'   => 2,
  19.     'body' => [
  20.         'id'          => 2,
  21.         'city'        => '上海市',
  22.         'description' => '上海市(Shanghai City),简称“沪” ,别称“申”,中华人民共和国直辖市、国家中心城市、超大城市、上海大都市圈核心城市、国家历史文化名城 [206],是中国gcd的诞生地。上海市入围世界Alpha+城市, 基本建成国际经济、金融、贸易、航运中心,形成具有全球影响力的科技创新中心基本框架。截至2022年12月底,上海市辖16个区,107个街道、106个镇、2个乡。',
  23.         'population'  => '2487',
  24.         'area'        => '6341',
  25.     ]
  26. ];
  27. $params = [
  28.     'index' => 'php_index',
  29.     'id'   => 3,
  30.     'body' => [
  31.         'id'          => 3,
  32.         'city'        => '天津市',
  33.         'description' => '天津市(Tianjin City),简称“津”,别称津沽、津门,是中华人民共和国省级行政区、直辖市、国家中心城市、超大城市 [222],地处中华人民共和国华北地区,海河流域下游,东临渤海,北依燕山,西靠首都北京市,其余均与河北省相邻。截至2023年10月,天津市共辖16个区。',
  34.         'population'  => '1364',
  35.         'area'        => '11966',
  36.     ]
  37. ];
  38. $params = [
  39.     'index' => 'php_index',
  40.     'id'   => 4,
  41.     'body' => [
  42.         'id'          => 4,
  43.         'city'        => '重庆市',
  44.         'description' => '重庆市,简称“渝”, 别称山城、江城,是中华人民共和国直辖市、国家中心城市、超大城市,国务院批复的国家重要中心城市之一、长江上游地区经济中心, 国际消费中心城市,全国先进制造业基地、西部金融中心、西部科技创新中心、 国际性综合交通枢纽城市和对外开放门户,辖38个区县',
  45.         'population'  => '3191',
  46.         'area'        => '82400',
  47.     ]
  48. ];
复制代码

  • 增 多条
  1. 返回数组
  2. //假设MySQL查询出来的数据如下
  3. $mysql_data = [
  4.     [
  5.         'id'          => 1024,
  6.         'city'        => 'xx市',
  7.         'description' => 'xxxx',
  8.         'population'  => '6666',
  9.         'area'        => '6666',
  10.     ],
  11.     [
  12.         'id'          => 1025,
  13.         'city'        => 'yy市',
  14.         'description' => 'yyyy',
  15.         'population'  => '8888',
  16.         'area'        => '8888',
  17.     ]
  18. ];
  19. //由于ES插入的要求,需要将插入数据的格式转化,为此可以封装一个方法
  20. function esBatchInsert($index_name, $mysql_data) {
  21.     $params = [];
  22.     foreach($mysql_data as $v) {
  23.         $params['body'][] = ['index' => ['_index' => $index_name, '_id' => $v['id']],];
  24.         $params['body'][] = $v;
  25.     }
  26.     return $params;
  27. }
  28. $response = $client->bulk(esBatchInsert('php_index', $mysql_data));
  29. dd($response->asArray());
  30. 可根据返回的数据再次循环,排查失败掉的漏网之鱼
复制代码

  • 删 单条
  1. 返回bool
  2. $params = [
  3.     'index' => 'php_index',
  4.     'id'    => '1025'
  5. ];
  6. $response = $client->delete($params);
  7. dd($response->asBool());
复制代码

  • 删 多条
  1. 方式1:
  2. 返回mixed
  3. for($i = 1000; $i < 1050; $i++) { //模拟要删除这些数据
  4.     $params = [
  5.         'index' => 'php_index',
  6.         'id'    => $i
  7.     ];
  8.     if(! $client->exists($params)->asBool()) {
  9.         continue;
  10.     }
  11.     $response = $client->delete($params)->asBool();
  12.     if(! $response) {
  13.         //若删除失败,请添加其它操作,记录日志或存入队列,进行重试或者人工介入
  14.     }
  15. }
  16. 方式2:
  17. 返回mixed
  18. for($i = 1000; $i < 1050; $i++) { //模拟要删除这些数据
  19.     $params['body'][] = [
  20.         'delete' => [
  21.             '_index' => 'php_index',
  22.             '_id' => $i,
  23.         ]
  24.     ];
  25. }
  26. $response = $client->bulk($params)->asArray();
  27. if ($response['errors']) {
  28.     foreach ($response['items'] as $item) {
  29.         if (isset($item['delete']['status']) && ($item['delete']['status'] != 200)) {
  30.             //若删除失败,请添加其它操作,记录日志或存入队列,进行重试或者人工介入
  31.         }
  32.     }
  33. } else {
  34.     echo "批量删除成功!";
  35. }
复制代码

  • 删 文档的某个字段
  1. 返回bool
  2. $params = [
  3.     'index' => 'php_index',
  4.     'id' => 1,
  5.     'body' => [
  6.         'script' => [
  7.             'source' => 'ctx._source.remove(params.field)',
  8.             'params' => [
  9.                 'field' => '要删除的字段名'
  10.             ]
  11.         ]
  12.     ]
  13. ];
  14. $response = $client->update($params);
  15. dd($response->asBool());
复制代码

  • 改 直接修改
  1. 返回bool
  2. $params = [
  3.     'index' => 'php_index',
  4.     'id'    => 1,
  5.     'body'  => [
  6.         'doc' => [
  7.             'city' => '北京' //这里是要修改的字段,把北京市改为北京
  8.         ]
  9.     ]
  10. ];
  11. $response = $client->update($params);
  12. dd($response->asBool());
复制代码

  • 改 自增
  1. 返回bool
  2. 官方文档演示有误,请按照以下正确写法。
  3. $params = [
  4.     'index' => 'php_index',
  5.     'id'    => 1,
  6.     'body'  => [
  7.         'script' => [
  8.                 //表达式
  9.             'source' => 'ctx._source.population += params.population', //给北京人口加4万,population为自定义文档字段,其余字符固定写法。
  10.             //表达式所使用的变量
  11.             'params' => [
  12.                 'population' => 4
  13.             ],
  14.         ],
  15.     ]
  16. ];
  17. $response = $client->update($params);
  18. dd($response->asBool());
复制代码

  • 改 若文档不存在,则插入
  1. $params = [
  2.     'index' => 'php_index',
  3.     'id'    => 60, //若id对应的文档不存在,则利用upsert段的数据,重新生成一个id为60的文档。
  4.     'body'  => [
  5.         'doc' => [
  6.             'city' => '台北市'
  7.         ],
  8.         'upsert' => [
  9.             'append_field' => 1
  10.         ],
  11.     ]
  12. ];
  13. $response = $client->update($params);
  14. dd($response->asBool());
复制代码

  • 改 批量
  1. //假设以下数据时数据表中查询出来的字段,要修改以下内容
  2. $mysql_data = [
  3.     ['id' => 1, 'city' => '北京'],
  4.     ['id' => 2, 'city' => '上海'],
  5. ];
  6. //可以封装一个方法,格式化数据
  7. function esBatchUpdate($index_name, $update_data) {
  8.     if(! $update_data) {
  9.         return [];
  10.     }
  11.     $arr = [];
  12.     foreach($update_data as $v) {
  13.         $arr[] = ['update' => ['_index' => $index_name, '_id' => $v['id']]];
  14.         unset($v['id']);
  15.         $arr[] = ['doc' => $v];
  16.     }
  17.     return ['body' => $arr];
  18. }
  19. $response = $client->bulk(esBatchUpdate('php_index', $mysql_data));
  20. $response = $response->asArray();
  21. //处理
  22. if ($response['errors']) {
  23.     foreach ($response['items'] as $item) {
  24.         if (isset($item['update']['status']) && ($item['update']['status'] != 200)) {
  25.             //若删除失败,请添加其它操作,记录日志或存入队列,进行重试或者人工介入
  26.         }
  27.     }
  28. } else {
  29.     echo "批量删除成功!";
  30. }
复制代码

  • 改 追加新的字段
  1. $params = [
  2.     'index' => 'php_index',
  3.     'id' => '1',
  4.     'body' => [
  5.         'doc' => [
  6.             'new_field' => 'new_value'
  7.         ],
  8.     ]
  9. ];
  10. $response = $client->update($params);
复制代码

  • 改 删除某些字段
  1. 返回bool
  2. $params = [
  3.     'index' => 'php_index',
  4.     'id' => 1,
  5.     'body' => [
  6.         'script' => [
  7.             'source' => 'ctx._source.remove(params.field)',
  8.             'params' => [
  9.                 'field' => '要删除的字段名'
  10.             ]
  11.         ]
  12.     ]
  13. ];
  14. $response = $client->update($params);
  15. dd($response->asBool());
复制代码
PHP ES  Api针对Doc高级查询

查询关键词官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/term-level-queries.html

  • 指定id查找
  1. 返回string
  2. $params = [
  3.     'index' => 'php_index',
  4.     'id'    => 1,
  5. ];
  6. $response =  $client->get($params);
  7. echo $response->asString();
  8. 得到以下结果
  9. {
  10.     "_index": "php_index",
  11.     "_id": "1",
  12.     "_version": 1,
  13.     "_seq_no": 0,
  14.     "_primary_term": 1,
  15.     "found": true,
  16.     "_source": {
  17.         "id": 1,
  18.         "city": "北京市",
  19.         "description": "北京市(Beijing),简称“京”,古称燕京、北平,是中华人民共和国首都、直辖市、国家中心城市、超大城市, 国务院批复确定的中国政治中心、文化中心、国际交往中心、科技创新中心, 中国历史文化名城和古都之一,世界一线城市",
  20.         "population": "2186",
  21.         "area": "16411"
  22.     }
  23. }
复制代码

  • 查找全部
  1. 返回array
  2. $response['hits']['total']['value']可获取条数
  3. $params = [
  4.     'index' => 'php_index',
  5.     'body'  => [
  6.         'query' => [
  7.             'match_all' => new StdClass
  8.         ]
  9.     ]
  10. ];
  11. $response = $client->search($params);
  12. dd($response->asArray());
复制代码

  • 指定指定部门id的数据。
  1. 返回数组
  2. $response['hits']['total']['value']可获取条数
  3. $params = [
  4.     'index' => 'php_index',
  5.     'body' => [
  6.         'query' => [
  7.             'ids' => [
  8.                 'values' => [1, 2]
  9.             ]
  10.         ]
  11.     ]
  12. ];
  13. $response = $client->search($params);
  14. dd($response->asArray());
复制代码

  • 分页查询
  1. 返回数组
  2. //传输的页码
  3. $page = 2;
  4. $size = 2;
  5. //偏移量算法
  6. $offset = ($page -1 ) * $size;
  7. $params = [
  8.     'index' => 'php_index',
  9.     'body' => [
  10.         'from' => $offset,
  11.         'size' => $size,
  12.         // 可以添加其他查询条件
  13.         'query' => [
  14.             'match_all' => new \stdClass()
  15.         ]
  16.     ]
  17. ];
  18. $response = $client->search($params);
  19. dd($response->asArray());
复制代码

  • 返回指定字段
  1. 返回数组
  2. $params = [
  3.     'index' => 'php_index',
  4.     'body' => [
  5.         '_source' => ['description'], //自定义字段
  6.         'query' => [
  7.             'match_all' => new \stdClass()
  8.         ]
  9.     ]
  10. ];
  11. $response = $client->search($params);
  12. dd($response->asArray());
复制代码

  • 判断是否存在
  1. 返回bool
  2. $params = [
  3.     'index' => 'php_index',
  4.     'id'    => 10
  5. ];
  6. $response = $client->exists($params);
复制代码

  • 获取条数
  1. 返回int
  2. $params = [
  3.     'index' => 'php_index',
  4.     'body' => [
  5.         'query' => [
  6.             'match_all' => new StdClass
  7.         ]
  8.     ]
  9. ];
  10. $response = $client->count($params);
  11. dd($response->asArray()['count'] ?? 0);
复制代码

  • 高亮查询(类比百度词条对关键字的标红行为)
  1. 返回string
  2. echo "";
  3. $params = [
  4.     'index' => 'php_index',
  5.     'body'  => [
  6.         'query' => [
  7.             'match' => [
  8.                 'description' => '北京' //返回该字段含有北京或北或京的文字。
  9.             ]
  10.         ],
  11.         'highlight' => [
  12.             'fields' => [
  13.                 'city' => ['pre_tags' => ['<em>'], 'post_tags' => ['</em>'],], //配置要高亮的字段
  14.                 'description' => ['pre_tags' => ['<em>'], 'post_tags' => ['</em>'],] //配置要高亮的字段
  15.             ]
  16.         ]
  17.     ]
  18. ];
  19. $response = $client->search($params);
  20. print_r($response->asString());
  21. 返回格式如下,具体要用那个字段,看具体需求
  22. {
  23.   "took":13,
  24.   "timed_out":false,
  25.   "_shards":{
  26.     "total":1,
  27.     "successful":1,
  28.     "skipped":0,
  29.     "failed":0
  30.   },
  31.   "hits":{
  32.     "total":{
  33.       "value":2,
  34.       "relation":"eq"
  35.     },
  36.     "max_score":2.9070516,
  37.     "hits":[
  38.       {
  39.         "_index":"php_index",
  40.         "_id":"1",
  41.         "_score":2.9070516,
  42.         "_source":{
  43.           "id":1,
  44.           "city":"北京",
  45.           "description":"北京市(Beijing),简称“京”,古称燕京、北平,是中华人民共和国首都、直辖市、国家中心城市、超大城市, 国务院批复确定的中国政治中心、文化中心、国际交往中心、科技创新中心, 中国历史文化名城和古都之一,世界一线城市",
  46.           "population":2198,
  47.           "area":"16411",
  48.           "new_field":"new_value"
  49.         },
  50.         "highlight":{
  51.           "description":["<em>北</em><em>京</em>市(Beijing),简称“<em>京</em>”,古称燕<em>京</em>、<em>北</em>平,是中华人民共和国首都、直辖市、国家中心城市、超大城市, 国务院批复确定的中国政治中心、文化中心、国际交往中心、科技创新中心, 中国历史文化名城和古都之一"]
  52.         }
  53.       },
  54.       {
  55.         "_index":"php_index",
  56.         "_id":"3",
  57.         "_score":2.5460577,
  58.         "_source":{
  59.           "id":3,
  60.           "city":"天津市",
  61.           "description":"天津市(Tianjin City),简称“津”,别称津沽、津门,是中华人民共和国省级行政区、直辖市、国家中心城市、超大城市 [222],地处中华人民共和国华北地区,海河流域下游,东临渤海,北依燕山,西靠首都北京市,其余均与河北省相邻。截至2023年10月,天津市共辖16个区。",
  62.           "population":"1364",
  63.           "area":"11966"
  64.         },
  65.         "highlight":{
  66.           "description":["天津市(Tianjin City),简称“津”,别称津沽、津门,是中华人民共和国省级行政区、直辖市、国家中心城市、超大城市 [222],地处中华人民共和国华<em>北</em>地区,海河流域下游,东临渤海,<em>北</em>依燕山,西靠首都<em>北</em><em>京</em>市",",其余均与河<em>北</em>省相邻。"]
  67.         }
  68.       }
  69.     ]
  70.   }
  71. }
复制代码

  • 限量 可参考分页逻辑(类比MySQL limit)
  1. 返回array
  2. $params = [
  3.     'index' => 'php_index',
  4.     'body'  => [
  5.         'query' => [
  6.             'match_all' => new stdClass
  7.         ],
  8.         'from'  => 0,
  9.         'size'  => 1,
  10.     ]
  11. ];
  12. $response = $client->search($params);
  13. dd($response->asArray());
复制代码

  • 定值查找 (类比MySQL wher filed = ‘kw’)
    keyword 或 integer 等非分词字段:可用 term 准确匹配。如果字段是 text 类型,那么 term 查询无法找到预期的匹配结果。
    text 类型并且你想要准确匹配,可以使用 match_phrase 查询
  1. 方式1 针对integer字段的精准匹配
  2. $params = [
  3.     'index' => 'php_index',
  4.     'body'  => [
  5.         'query' => [
  6.             'term' => [
  7.                 'city' => '北京市' //北京或北或京无法查询出指定数据
  8.             ]
  9.         ]
  10.     ]
  11. ];
  12. $response = $client->search($params);
  13. dd($response->asArray());
复制代码

  • 分词查找(类比MySQL where filed like '%kw%' or filed like '%k%' or filed like '%w%')
  1. 方式1
  2. 返回array
  3. 这种方式仅支持text类型
  4. $params = [
  5.     'index' => 'php_index',
  6.     'body'  => [
  7.         'query' => [
  8.             'match' => [
  9.                 'description' => '北京'
  10.             ]
  11.         ]
  12.     ]
  13. ];
  14. $response = $client->search($params);
  15. dd($response->asArray());
  16. 方式2
  17. 返回array
  18. 非text类型,可手动分词
  19. $params = [
  20.     'index' => 'php_index',
  21.     'body'  => [
  22.         'query' => [
  23.             'bool' => [
  24.                 'should' => [ //or
  25.                     [
  26.                         'match' => ['city' => '北京']
  27.                     ],
  28.                     [
  29.                         'match' => ['city' => '北京市']
  30.                     ]
  31.                 ],
  32.                 'minimum_should_match' => 1
  33.                 //minimum_should_match 设置为 1,表示至少需要匹配一个 should 子句中的条件
  34.             ]
  35.         ]
  36.     ]
  37. ];
  38. $response = $client->search($params);
  39. dd($response->asArray());
复制代码

  • 模糊匹配 (类比MySQL where filed like  '%kw%')wildcard性能可能不如别的类型的查询,如match查询,因为wildcard查询必要对每个文档的字段值进行模式匹配
  1. 方式1,针对keyword mapping
  2. 返回array
  3. $params = [
  4.     'index' => 'php_index',
  5.     'body'  => [
  6.         'query' => [
  7.             'wildcard' => [
  8.                 'city' => '*北京*' //*表示任意字符,?表示任意一个字符
  9.             ]
  10.         ]
  11.     ]
  12. ];
  13. $response = $client->search($params);
  14. dd($response->asArray());
  15. 方式2,针对text mapping,并非严格意义上的MySQL where filed like  '%kw%',而是 where filed like '%kw%' or filed like '%k%' or filed like '%w%'
  16. 返回array
  17. $params = [
  18.     'index' => 'php_index',
  19.     'body'  => [
  20.         'query' => [
  21.             'match' => [
  22.                 'description' => '北京'
  23.             ]
  24.         ]
  25.     ]
  26. ];
  27. $response = $client->search($params);
  28. dd($response->asArray());
复制代码

  • 前缀查找 (类比MySQL where filed like  'kw%')针对keyword类型的字段有效
  1. 返回array
  2. $params = [
  3.     'index' => 'php_index',
  4.     'body'  => [
  5.         'query' => [
  6.             'prefix' => [
  7.                 'city' => '北'
  8.             ]
  9.         ]
  10.     ]
  11. ];
  12. $response = $client->search($params);
复制代码

  • 后缀查找 (类比MySQL where filed like  '%kw')针对keyword字段有效
  1. $params = [
  2.     'index' => 'php_index',
  3.     'body'  => [
  4.         'query' => [
  5.             'wildcard' => [
  6.                 'city' => '*京市'
  7.             ]
  8.         ]
  9.     ]
  10. ];
  11. $response = $client->search($params);
复制代码

  • 区间查找(类比MySQL where field =、between)
  1. 返回array
  2. <是lt、<=是lte、>是gt、>=是gte
  3. $params = [
  4.     'index' => 'php_index',
  5.     'body'  => [
  6.         'query' => [
  7.             'range' => [
  8.                 'area' => [ //面积大于1000平方千米的城市
  9.                     'gt' => 1000
  10.                 ]
  11.             ]
  12.         ]
  13.     ]
  14. ];
  15. $response = $client->search($params);
  16. dd($response->asArray());
  17. 返回array
  18. between
  19. $params = [
  20.     'index' => 'php_index',
  21.     'body'  => [
  22.         'query' => [
  23.             'range' => [
  24.                 'area' => [ //获取面积大于1000平方千米,但在10000平方千米以内的城市数据
  25.                     'gt' => 1000,
  26.                     'lt' => 10000,
  27.                 ]
  28.             ]
  29.         ]
  30.     ]
  31. ];
  32. $response = $client->search($params);
  33. dd($response->asArray());
复制代码

  • 正则匹配(类比MySQL where field regexp 'xxx')针对keyword字段有效
  1. $params = [
  2.     'index' => 'php_index',
  3.     'body'  => [
  4.         'query' => [
  5.             'regexp' => [
  6.                 'city' => '.*北京.*' //搜索包含北京关键字的字段
  7.             ]
  8.         ]
  9.     ]
  10. ];
  11. $response = $client->search($params);
  12. dd($response->asArray());
  13. .*: 匹配任意数量的任意字符
  14. .: 匹配任意单个字符。
  15. *: 匹配前面的元素零次或多次。
  16. +: 匹配前面的元素一次或多次。
  17. ?: 匹配前面的元素零次或一次。
  18. ^: 匹配字符串的开头。
  19. $: 匹配字符串的结尾。
  20. [...]: 匹配方括号中的任意字符。
  21. {n}: 匹配前面的元素恰好 n 次。
  22. {n,}: 匹配前面的元素至少 n 次。
  23. {n,m}: 匹配前面的元素至少 n 次,但不超过 m 次。
复制代码

  • 取反查找(类比MySQL where filed != 'kw')针对text类型的字段无效
  1. 返回bool
  2. $params = [
  3.     'index' => 'php_index',
  4.     'body'  => [
  5.         'query' => [
  6.             'bool' => [
  7.                 'must_not' => [
  8.                     'term' => [
  9.                         'city' => '北京市' //返回不是北京市的数据
  10.                     ]
  11.                 ]
  12.             ]
  13.         ]
  14.     ]
  15. ];
  16. $response = $client->search($params);
  17. dd($response->asArray());
  18. $params = [
  19.     'index' => 'php_index',
  20.     'body'  => [
  21.         'query' => [
  22.             'bool' => [
  23.                 'must_not' => [
  24.                     'range' => [
  25.                         'area' => [ //面积不小于1000平方千米的城市
  26.                             'lt' => 1000
  27.                         ]
  28.                     ]
  29.                 ]
  30.             ]
  31.         ]
  32.     ]
  33. ];
  34. $response = $client->search($params);
  35. dd($response->asArray());
复制代码

  • 多条件and查找(类比MySQL where expression1 and expression2)
  1. 返回array
  2. $params = [
  3.     'index' => 'php_index',
  4.     'body' => [
  5.         'query' => [
  6.             'bool' => [
  7.                 'must' => [ //返回city字段是北京市,并且描述带有首都的数据
  8.                     ['term' => ['city' => '北京市']],
  9.                     ['match' => ['description' => '首都']],
  10.                 ]
  11.             ]
  12.         ]
  13.     ]
  14. ];
  15. $response = $client->search($params);
  16. dd($response->asArray());
复制代码

  • 多条件or查找(类比MySQL where expression1 or expression2)
  1. 返回array
  2. $params = [
  3.     'index' => 'php_index',
  4.     'body' => [
  5.         'query' => [
  6.             'bool' => [
  7.                 'should' => [ //查询城市名北京市,或者描述含有沪的描述内容
  8.                     ['term' => ['city' => '北京市']],
  9.                     ['match' => ['description' => '沪']],
  10.                 ]
  11.             ]
  12.         ]
  13.     ]
  14. ];
  15. $response = $client->search($params);
  16. dd($response->asArray());
复制代码

  • and 和 or 共同使用
  1. $params = [
  2.     'index' => 'php_index',
  3.     'body'  => [
  4.         'query' => [
  5.             'bool' => [ //查询城市名为北京市或上海市,并且描述带有京字的数据
  6.                 'must' => [
  7.                     [
  8.                         'bool' => [
  9.                             'should' => [
  10.                                 ['term' => ['city' => '北京市']],
  11.                                 ['term' => ['city' => '上海市']]
  12.                             ]
  13.                         ]
  14.                     ],
  15.                     ['match' => ['description' => '京']]
  16.                 ]
  17.             ]
  18.         ]
  19.     ]
  20. ];
  21. $response = $client->search($params);
  22. dd($response->asArray());
复制代码

  • 排序(类比MySQL Order By)
  1. 单字段排序
  2. $params = [
  3.     'index' => 'php_index',
  4.     'body'  => [
  5.         'query' => [
  6.             'match_all' => new StdClass,
  7.         ],
  8.         'sort' => [ //四个直辖市数据按照区域大小排名
  9.             ['area' => ['order' => 'asc']] //asc或desc
  10.         ]
  11.     ]
  12. ];
  13. $response = $client->search($params);
  14. dd($response->asArray());
  15. 多字段排序
  16. $params = [
  17.     'index' => 'php_index',
  18.     'body'  => [
  19.         'query' => [
  20.             'match_all' => new StdClass,
  21.         ],
  22.         'sort' => [ //区域按照降序,人口按照升序排,条件不会冲突,回想MySQL order by那样,合并处理。
  23.             ['area' => ['order' => 'asc']], //asc或desc
  24.             ['population' => ['order' => 'desc']], //asc或desc
  25.         ]
  26.     ]
  27. ];
复制代码

  • 聚合函数(类比MySQL聚合函数)
  1. 返回bool
  2. $params = [
  3.     'index' => 'php_index',
  4.     'body'  => [
  5.         'size' => 0,  // 设置为0表示不返回实际的文档,仅返回聚合结果
  6.         'aggs' => [
  7.             'population_data' => [ //这个key为自定义名称
  8.                 'avg' => [ //返回4个直辖市平均人口
  9.                     'field' => 'population'
  10.                 ]
  11.             ]
  12.         ]
  13.     ]
  14. ];
  15. $response = $client->search($params);
  16. dd($response->asArray());
  17. avg : 平均值
  18. sum :总和
  19. min : 最小值
  20. max :最大值
  21. 没有count。
复制代码

  • 分组(类比MySQL Group By)
  1. 返回string
  2. $params = [
  3.     'index' => 'php_index',
  4.     'body'  => [
  5.         'size' => 0,  // 不返回文档,只返回聚合结果
  6.         'aggs' => [
  7.             'city_group' => [ //自定义名称
  8.                 'terms' => [
  9.                     'field' => 'city',
  10.                     'size'  => 10  // 聚合结果的数量限制
  11.                 ]
  12.             ]
  13.         ]
  14.     ]
  15. ];
  16. $response = $client->search($params)->asArray();
  17. $aggregations = $response['aggregations']['city_group']['buckets'];
  18. foreach ($aggregations as $bucket) {
  19.     echo "城市名:" . $bucket['key'] . " - 本组组对应的数量:" . $bucket['doc_count'] . "\n";
  20. }
  21. 城市名:上海市 - 本组组对应的数量:1
  22. 城市名:北京市 - 本组组对应的数量:1
  23. 城市名:天津市 - 本组组对应的数量:1
  24. 城市名:重庆市 - 本组组对应的数量:1
复制代码

  • 合并(类比MySQL union)
    用PHP array_merge实现吧,这对于ES不适用。
  • 指定数据靠前(类比竞价排名)
  1. 返回array
  2. 个人还是推荐使用自定义字段,因为['hits']['_score']字段得出来分数不可控。
  3. 搜索城市,原先是北京靠前,现在通过修改权重,使其上海靠前
  4. $params = [
  5.     'index' => 'php_index',
  6.     'body' => [
  7.         'query' => [
  8.             'function_score' => [
  9.                 'query' => [
  10.                     'bool' => [
  11.                         'should' => [
  12.                             ['term' => ['city' => '北京市']],
  13.                             ['match' => ['description' => '沪']]
  14.                         ]
  15.                     ]
  16.                 ],
  17.                 'functions' => [
  18.                     [
  19.                         'filter' => [
  20.                             'match' => ['description' => '沪']
  21.                         ],
  22.                         'weight' => 2  // 增加包含“沪”的文档的权重
  23.                     ]
  24.                 ],
  25.                 'boost_mode' => 'sum'
  26.             ]
  27.         ],
  28.         'sort' => [
  29.             '_score' => [
  30.                 'order' => 'desc'  // 按照得分降序排序
  31.             ]
  32.         ]
  33.     ]
  34. ];
  35. $response = $client->search($params);
  36. dd($response->asArray());
  37. boost_mode设定了如何将查询的基础得分(由 query 部分确定)与功能得分(由 functions 部分计算)进行组合。以下是几种常用的 boost_mode 设置:
  38. multiply: 基础得分与功能得分相乘。
  39. replace: 功能得分替代基础得分。
  40. sum: 基础得分与功能得分相加。
  41. avg: 基础得分与功能得分的平均值。
  42. max: 取基础得分与功能得分中的最大值。
复制代码
Painless


  • 极简概括:是一种简单、安全的、服务于Elasticsearch的脚本语言。类比Redis或Nginx中的Lua,某些组件嵌入脚本语言用于实现复杂的逻辑,这并不罕见。
  • 官方文档:https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-guide.html
  • 使用场景:针对ES,例如上文在更新文档中,请求文档script段中的source段,都用的painless表达式。
  • 额外增补:由于painless语法内容过多,且比力简单,整个记录下来必要2万字,本钱题目,因此读者保举看手册。
  • 简单举例:
  1. //counter子对岸自增
  2. ctx._source.counter += params.count
  3. //if else 判断
  4. if (ctx._source.someField > 10) {
  5.     ctx._source.anotherField = ctx._source.someField * params.multiplier;
  6. } else {
  7.     ctx._source.anotherField = params.defaultValue;
  8. }
复制代码
IK中问分词与高级索引创建


  • 使用理由:ES默认的分词器对中文不友好,英文分词器会把中文每个字分开,因此必要专门的中文分词器。
  • 分词器的服务对象是映射,而不是索引。
  • 安装:
  1. 关闭ES
  2. 执行以下代码,注意版本号的问题
  3. bin/elasticsearch-plugin install https://get.infini.cloud/elasticsearch/analysis-ik/8.14.1
  4. 进入交互界面输入Y。
  5. 之后启动ES
复制代码

  • ik_max_word与ik_smart分词精度控制演示:
  1. 演示分词:
  2. GET IP:9200/_analyze
  3. 传入以下内容
  4. {
  5.     "text":"射雕英雄传",
  6.     "analyzer":"ik_smart"
  7. }
  8. 返回
  9. {
  10.         "tokens": [
  11.                 {
  12.                         "token": "射雕英雄传",
  13.                         "start_offset": 0,
  14.                         "end_offset": 5,
  15.                         "type": "CN_WORD",
  16.                         "position": 0
  17.                 }
  18.         ]
  19. }
  20. 若使用ik_max_word
  21. {
  22.     "text":"射雕英雄传",
  23.     "analyzer":"ik_max_word"
  24. }
  25. 则返回
  26. {
  27.         "tokens": [
  28.                 {
  29.                         "token": "射雕英雄传",
  30.                         "start_offset": 0,
  31.                         "end_offset": 5,
  32.                         "type": "CN_WORD",
  33.                         "position": 0
  34.                 },
  35.                 {
  36.                         "token": "射雕",
  37.                         "start_offset": 0,
  38.                         "end_offset": 2,
  39.                         "type": "CN_WORD",
  40.                         "position": 1
  41.                 },
  42.                 {
  43.                         "token": "英雄传",
  44.                         "start_offset": 2,
  45.                         "end_offset": 5,
  46.                         "type": "CN_WORD",
  47.                         "position": 2
  48.                 },
  49.                 {
  50.                         "token": "英雄",
  51.                         "start_offset": 2,
  52.                         "end_offset": 4,
  53.                         "type": "CN_WORD",
  54.                         "position": 3
  55.                 },
  56.                 {
  57.                         "token": "传",
  58.                         "start_offset": 4,
  59.                         "end_offset": 5,
  60.                         "type": "CN_CHAR",
  61.                         "position": 4
  62.                 }
  63.         ]
  64. }
复制代码

  • 设置自定义分词:
  1. 有些场景,有很多的专业用语,但是IK分词器把它拆分开,就显得不是很精准,因此可以添加自定义分词解决。
  2. vim ES安装目录/config/analysis-ik/IKAnalyzer.cfg.xml
  3. 在<entry key="ext_dict"></entry>的双标签中间写入文件名,例如
  4. <entry key="ext_dict">self_words.dic</entry>
  5. vim self_words.dic
  6. 逐行添加自定义词汇
  7. 重启ES。
复制代码

  • PHP使用:
  1. 返回bool
  2. $params = [
  3.     'index' => 'test_index',
  4.     'body' => [
  5.         'settings' => [
  6.             'analysis' => [
  7.                 'analyzer' => [
  8.                     'analyzer_ik_max_word' => [
  9.                         'type' => 'ik_max_word' //ik分词器内置关键配置,更多的分词结果
  10.                     ],
  11.                     'analyzer_ik_smart' => [
  12.                         'type' => 'ik_smart' //ik分词器内置关键配置,更快的分词结果
  13.                     ]
  14.                 ]
  15.             ]
  16.         ],
  17.         'mappings' => [
  18.             'properties' => [
  19.                 'content' => [
  20.                     'type' => 'text',
  21.                     'analyzer' => 'analyzer_ik_smart',  // 设置索引时的分词器
  22.                     'search_analyzer' => 'analyzer_ik_smart' // 设置搜索时的分词器
  23.                 ]
  24.             ]
  25.         ]
  26.     ]
  27. ];
  28. $response = $client->indices()->delete(['index' => 'test_index']);
  29. dump($response->asBool());
复制代码

  • 进阶用法,添加过滤(不生效):
  1. 返回bool
  2. 这里尝试创建了一个更复杂的索引,添加了过滤器,但是不生效,不知道是那里的问题。
  3. 如下,按照以下索引的配置,过滤后的结果,应当是"C世界上最好编程语言",然后再分词,可却不生效。
  4. GET IP:9200/test_index/_analyze
  5. {
  6.     "analyzer":"self_ik_max_word",
  7.     "text" : "PHP是世界上最好的编程语言"
  8. }
  9. $params = [
  10.     'index' => 'test_index',  // 指定要创建的索引名称
  11.     'body' => [
  12.         'settings' => [  // 配置索引的设置
  13.             'analysis' => [  // 分析器设置
  14.                 'char_filter' => [  // 字符过滤器设置
  15.                     'self_char_filter' => [  // 自定义字符过滤器名称
  16.                         'type' => 'mapping',  // 过滤器类型为映射
  17.                         'mappings' => ['PHP => C']  // 替换分词的字符
  18.                     ]
  19.                 ],
  20.                 'filter' => [  // 过滤器设置
  21.                     'self_filter' => [  // 自定义停用词过滤器名称
  22.                         'type' => 'stop',  // 过滤器类型为停用词
  23.                         'stopwords' => ['是', '的']  // 停用词列表
  24.                     ]
  25.                 ],
  26.                 'analyzer' => [  // 分析器设置
  27.                     'self_ik_max_word' => [  // IK 分词器名称
  28.                         'type' => 'ik_max_word',  // 使用 IK 分词器的最大分词模式
  29.                         'char_filter' => ['html_strip', 'self_char_filter'], // html_strip过滤器会把html标签忽略,但html转义字符仍旧生效( 仍旧是空格),且会把<br/>转化为\n
  30.                         'filter' => ['lowercase', 'self_filter'] //lowercase过滤器是将大写字母变为小写
  31.                     ],
  32.                     'self_ik_smart' => [  // IK 分词器名称
  33.                         'type' => 'ik_smart',  // 使用 IK 分词器的快速分词模式
  34.                         'char_filter' => ['html_strip', 'self_char_filter'],  // html_strip过滤器会把html标签忽略,但html转义字符仍旧生效( 仍旧是空格),且会把<br/>转化为\n
  35.                         'filter' => ['lowercase', 'self_filter'] //lowercase过滤器是将大写字母变为小写
  36.                     ]
  37.                 ]
  38.             ]
  39.         ],
  40.         'mappings' => [  // 配置索引的映射
  41.             'properties' => [  // 文档字段的属性设置
  42.                 'content' => [  // 文档中的字段名称
  43.                     'type' => 'text',  // 字段类型为文本
  44.                     'analyzer' => 'self_ik_max_word',  // 设置索引时的分词器
  45.                     'search_analyzer' => 'self_ik_max_word' // 设置搜索时的分词器
  46.                 ]
  47.             ]
  48.         ]
  49.     ]
  50. ];
  51. $response = $client->indices()->create($params);
  52. dd($response->asBool());
复制代码
ELK


  • 概念:ES结合LK作为ELK(Elasticsearch(搜索), Logstash(采集转换), Kibana(分析))组合,可用于及时监控、分析和可视化大量日记和事件数据,如系统日记、应用程序日记、网络流量日记等。
  • 构成

    • Elasticsearch:一个分布式搜索引擎,提供强大的搜索功能和及时的数据分析能力。
    • Logstash:一个数据处理管道,用于收集、解析和转发日记数据。
    • Kibana:一个数据可视化工具,帮助用户通过图形化界面检察和分析 Elasticsearch 中的数据。

  • 作用:

    • 日记管理:集中化日记收集:通过Logstash收集来自不同系统和应用的日记,统一存储在Elasticsearch中。
    • 日记分析:利用Kibana对日记数据进行及时分析和可视化,帮助发现系统题目和异常。
    • 及时监控:跟踪应用程序的性能指标,及时检察应用的健康状态。
    • 性能瓶颈检测:通过分析日记数据,识别息争决性能瓶颈。
    • 安全事件分析:监控和分析系统中的安全事件,检测异常行为。
    • 合规性审计:记录和分析系统日记,以满足合规性要求。
    • 数据可视化:通过Kibana创建各种图表和仪表盘,帮助业务分析师明白数据趋势和模式。
    • 用户行为分析:分析用户的操作日记,优化用户体验和产品计划。
    • 服务器监控:跟踪服务器的性能指标,如CPU使用率、内存使用环境和磁盘空间。
    • 应用状态监控:监控应用程序的运行状态和日记,以确保正常运行。
    • 题目诊断:利用Elasticsearch存储的日记数据,快速定位息争决系统故障。
    • 根因分析:分析相关日记,帮助找到题目的根本原因。

  • 对于PHP而言:几乎用不到,这是Java和大数据方向的。
Kibana

  1. 保证ES服务已启动。
  2. 防火墙开启5601端口
  3. firewall-cmd --add-port=5601/tcp --zone=public --permanent
  4. systemctl restart firewalld
  5. 下载与解压
  6. curl -O https://artifacts.elastic.co/downloads/kibana/kibana-8.14.1-linux-x86_64.tar.gz
  7. tar zxf kibana-8.14.1-linux-x86_64.tar.gz
  8. 权限配置
  9. chown -R es:es kibana-8.14.1
  10. 切换用户
  11. su es
  12. kibana不支持elastic用户,所以需要创建新用户,并赋予超级管理员角色,并赋予kibana_system角色
  13. elasticsearch-users useradd zs
  14. elasticsearch-users roles -a superuser zs
  15. 少了这一步报错,让我搞了4个小时。
  16. elasticsearch-users roles -a kibana_system zs
  17. 修改配置
  18. vim kibana-8.14.1/config/kibana.yml
  19. elasticsearch.username: "zs"
  20. elasticsearch.password: "123456"
  21. elasticsearch.hosts: ["ES IP:9200"]
  22. i18n.locale: "zh-CN"
  23. 启动
  24. kibana-8.14.1/bin/kibana
  25. 过2分钟后,访问http://IP:5601
复制代码
4种和数据库同步方案


  • 不妨先讲一讲业务层是怎么使用ES的读功能的:
    以电商系统为例,用到ES的原因,一个是商品数目巨大,一个是分词有助于展示更好的结果,上架的商品因为关键词误差搜不到,这就是损失。
    例如商品列表数据的展示,可将价格,名称,形貌,主图片,标签,id等其他数据存入ES,然后展示。
    当用户点击某个商品时,根据id进行哈希运算,获取商品数据在谁人MySQL分表中,利用id主键索引极速查询的特性,快速获取商品数据。
  • 同步双写:MySQL和ES同步更新

    • 优点:实现简单,及时性高。
    • 缺点:耦合度高,其中一个组件异常可能会影响另一个。

  • 异步双写:先同步MySQL,再用MQ同步ES。

    • 优点:优雅,由于MQ(非Redis实现的MQ)具有高可用机制,因此ES消费失败可以重试。
    • 缺点:多了一个MQ,就多了一层运维本钱。有延迟。

  • 主动化任务,定时遍历SQL:用时间戳做标识符,用于区分哪些数据未同步,没有同步就用脚本定时同步到ES。

    • 优点:业务逻辑层不必要额外的针对ES做写操作。
    • 缺点:及时性不够,对MySQL压力大。

  • 使用Canal基于Binlog进行靠近及时的同步,使用Canal监听MySQL Binlog,并部署同步ES数据的脚本,从而主动化保持同步。也可直接利用Canal同步ES。相关链接:https://github.com/alibaba/canal/wiki/Sync-ES

    • 优点:及时性高,对业务层代码无侵入。
    • 缺点:多了一个Canal,就多了一层运维本钱。

高并发下ES本身一致性解决方案


  • 题目:与上文讲的数据库一致性,不是一个东西。这里讲的是并发下ES本身更新数据导致的一致性题目。例如并发过来的两个请求,查询到结果是10,都想要-1,等两个执行完毕后,结果不是8而是9,那么就出现了数据一致性题目。
  • ES之外的解决方案:分布式锁。或非分布式环境下编程语言自带的具有排它性的锁。
  • ES乐观锁解决方案1:
  1. 背景:先创建一个num_test索引,并添加名为num的int类型的映射。并插入一条数据。
  2. 流程:当进行数据更新时,先做一次查询(get方法,不是search方法),获取相关的_primary_term,_seq_no值。
  3. 当更新数据时,添加对应的版本号,如果ES检测到版本号不对,则会报错,如下:
  4. $params = [
  5.     'index' => 'num_test',
  6.     'id'    => 1,
  7.     'body'  => [
  8.         'doc' => [
  9.             'num' => 10
  10.         ]
  11.     ],
  12.     'if_seq_no' => 3, // 使用序列号
  13.     'if_primary_term' => 1, // 使用主分片术语
  14. ];
  15. try {
  16.     $response = $client->update($params);
  17. } catch (\Exception $exception) {
  18.    echo '出错了,这里重试查询后再更新,或者记录错误等其它操作。。。'
  19. }
复制代码

  • ES乐观锁解决方案2(不生效,请勿使用):
  1. $params = [
  2.     'index' => 'num_test',
  3.     'id'    => 1,
  4.     'body'  => [
  5.         'doc' => [
  6.             'num' => 1800
  7.         ]
  8.     ],
  9.     'version' => 40, // 提供外部版本号
  10.     'version_type' => 'external' // 使用外部版本号
  11. ];
  12. try {
  13.     $response = $client->update($params); //版本不生效的方案,不推荐使用
  14. } catch (\Exception $exception) {
  15.     dump('出错了,这里进行重试,或者记录错误,等其它操作');
  16. }
复制代码

  • ES应对高并发写的报错题目(和上文内容不是一回事):ES针对大量的并发过来的写请求,ES支持的并不好,ES底层接纳乐观锁的形式,这会导致ES内部在频繁并发写入时内部维护版本号辩论,也就是说更新前查询出来的版本号,比当前实际的版本号小(被别的并发过来的请求增加了版本号),那就会报错,这也就是所谓的ES报版本辩论的错误的题目,对于这种场景,可添加重试次数,和业务层的异常获取作为兜底策略。重试代码示例如下:
  1. $params = [
  2.     'index' => 'index',
  3.     'id' => '10',
  4.     'body' => [
  5.         'doc' => [
  6.             'field1' => 'new value1',
  7.             'field2' => 'new value2'
  8.         ]
  9.     ],
  10.     'retry_on_conflict' => 3 // 设置重试次数
  11. ];
  12. try {
  13.     $response = $client->update($params);
  14. } catch (Exception $e) {
  15.     // 处理异常,可以选择记录日志或执行其它操作,这个catch是用来重试3次还报错的兜底策略。
  16. }
复制代码
为什么不消ES替代MySQL


  • ES没有MySQL的事务机制,高可用无法保证。
  • ES没有MySQL的关系型侧重,MySQL有强大的关联策略,MySQL join多张表时,ES必要手动实现。
  • ES的定位是快速索引快速查找,并非有过多高可用存储的机制,还是必要配合MySQL使用。
EQL


  • 极简概括:Event Query Language用于在ES中进行事件数据查询的类SQL语言。
  • 解决题目:为了更方便地分析时间序列数据和事件流数据,特殊适用于安全事件、日记数据和监控数据的分析。
  • 弃用原因:多用于快速调试。毕竟ES不是MySQL,SQL API 并不是ES中所有功能的完整替代品,有些复杂的查询和功能可能必要使用原生的ES查询 DSL(ES范畴或题目域计划的编程语言或语法)。
  • 简单示例:要查询索引下的一条数据
  1. POST IP:9200/_sql?format=json //类型可未txt,用制表符更直观的展示
  2. {
  3.   "query": "SELECT * FROM php_index WHERE city = '北京市'"
  4. }
  5. 结果:
  6. {
  7.         "columns": [
  8.                 {
  9.                         "name": "_boost",
  10.                         "type": "float"
  11.                 },
  12.                 {
  13.                         "name": "area",
  14.                         "type": "integer"
  15.                 },
  16.                 {
  17.                         "name": "city",
  18.                         "type": "keyword"
  19.                 },
  20.                 {
  21.                         "name": "description",
  22.                         "type": "text"
  23.                 },
  24.                 {
  25.                         "name": "id",
  26.                         "type": "long"
  27.                 },
  28.                 {
  29.                         "name": "population",
  30.                         "type": "integer"
  31.                 }
  32.         ],
  33.         "rows": [
  34.                 [
  35.                         null,
  36.                         16411,
  37.                         "北京市",
  38.                         "北京市(Beijing),简称“京”,古称燕京、北平,是中华人民共和国首都、直辖市、国家中心城市、超大城市, 国务院批复确定的中国政治中心、文化中心、国际交往中心、科技创新中心, 中国历史文化名城和古都之一,世界一线城市",
  39.                         1,
  40.                         2186
  41.                 ]
  42.         ]
  43. }
复制代码

  • 演示2:查询所有索引:
  1. POST IP:9200/_sql?format=txt
  2. {
  3.   "query": "show tables"
  4. }
  5.     catalog    |                       name                       |     type      |     kind      
  6. ---------------+--------------------------------------------------+---------------+---------------
  7. zs_es_cluster  |.alerts-default.alerts-default                    |VIEW           |ALIAS         
  8. zs_es_cluster  |.alerts-ml.anomaly-detection-health.alerts-default|VIEW           |ALIAS         
  9. zs_es_cluster  |.alerts-ml.anomaly-detection.alerts-default       |VIEW           |ALIAS         
  10. zs_es_cluster  |.alerts-observability.apm.alerts-default          |VIEW           |ALIAS         
  11. zs_es_cluster  |.alerts-observability.logs.alerts-default         |VIEW           |ALIAS         
  12. zs_es_cluster  |.alerts-observability.metrics.alerts-default      |VIEW           |ALIAS         
  13. zs_es_cluster  |.alerts-observability.slo.alerts-default          |VIEW           |ALIAS         
  14. zs_es_cluster  |.alerts-observability.threshold.alerts-default    |VIEW           |ALIAS         
  15. zs_es_cluster  |.alerts-observability.uptime.alerts-default       |VIEW           |ALIAS         
  16. zs_es_cluster  |.alerts-security.alerts-default                   |VIEW           |ALIAS         
  17. zs_es_cluster  |.alerts-stack.alerts-default                      |VIEW           |ALIAS         
  18. zs_es_cluster  |.alerts-transform.health.alerts-default           |VIEW           |ALIAS         
  19. zs_es_cluster  |.kibana-observability-ai-assistant-conversations  |VIEW           |ALIAS         
  20. zs_es_cluster  |.kibana-observability-ai-assistant-kb             |VIEW           |ALIAS         
  21. zs_es_cluster  |.siem-signals-default                             |VIEW           |ALIAS         
  22. zs_es_cluster  |my_index                                          |TABLE          |INDEX         
  23. zs_es_cluster  |num_test                                          |TABLE          |INDEX              
  24. zs_es_cluster  |php_index                                         |TABLE          |INDEX         
  25. zs_es_cluster  |test_index                                        |TABLE          |INDEX         
  26. zs_es_cluster  |zs_index                                          |TABLE          |INDEX         
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

来自云龙湖轮廓分明的月亮

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表