赞
踩
ES用的倒排索引算法。正倒两种索引都是用于快速检索数据的实现方案,我没有太官方的解释,所以举例说明:
分词就是把字符串拆分成有用的关键词,用于提供高质量搜索的数据源。
Java写的组件吃内存,建议VM虚拟机内存设置大一点,系统设置为1G内存。 开两个端口,并重启防火墙 firewall-cmd --add-port=9200/tcp --zone=public --permanent firewall-cmd --add-port=9300/tcp --zone=public --permanent systemctl restart firewalld 新建一个es用户,以非root形式运行,否则运行es会报错,java.lang.RuntimeException: can not run elasticsearch as root useradd -M es passwd es 密码为123456 vim /etc/security/limits.conf 文末添加两行配置,优化文件描述符软硬限制,对提高性能非常重要,文件描述符用于标识和管理每个进程都可以打开文件的数量 es soft nofile 65536 es hard nofile 65536 vim /etc/security/limits.d/20-nproc.conf 文末添加两行配置,优化文件描述符软硬限制,对提高性能非常重要,文件描述符用于标识和管理每个进程都可以打开文件的数量 es soft nofile 65536 es hard nofile 65536 vim /etc/sysctl.conf 定义系统中可以同时打开的最大文件描述符数量。 fs.file-max=655350 定义Linux内核中进程可以拥有的最大内存映射区域数量 vm.max_map_count=262144 重启 sysctl -p
下载tar包并解压,这个包地址来源于官网,并非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 启动ES,如果发现报错,请清空bin目录同级的data目录 ./bin/elasticsearch 启动后,直到看到如下字样,说明能成功启动,但是输入它生成的用户名密码,登不进去 然后Ctrl + C强制停止,因为启动一次之后,config/elasticsearch.yml配置文件,会发生变化,这一步不可少 Elasticsearch security features have been automatically configured! 登不进去,那就改配置 vim config/elasticsearch.yml 把91~103行的true全部改为false,如下,注意配置格式,key: value之间要留出空格,否则ES不识别对应的值。 # 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数据 rm -rf elasticsearch-8.14.1/data/* 再次执行,并使其后台运行 ./bin/elasticsearch -d 查看进程,确定ES是否成功执行 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/
上文配置的是没有密码的方案,倘若服务器IP和端口对外暴露,这不是一种安全的行为。
注意,要部署集群,各个节点密码应当一致。
注意配置格式,key: value之间要留出空格,否则ES不识别对应的值。
vim es根目录/config/elasticsearch.yml
修改以下配置
xpack.security.enabled: true
非root用户下启动es
./bin/elasticsearch -d
启动一个交互式命令行界面,从而设置密码,期间的几个交互,全部设置为123456
./bin/elasticsearch-setup-passwords interactive
默认用户名:elastic
密码:123456
ES中有些新的概念,可通过MySQL的概念去辅助记忆。
ES | MySQL | 备注 |
---|---|---|
Index(索引) | 库表 | / |
Type(类型) | 表 | 7及以上的版本被移除,原先是对标MySQL表的理念,后来发现这对于ES并非必须,就移除了 |
Documents(文档) | 行数据 | / |
Fields(字段) | 字段 | / |
Mapping(映射) | 表结构 | / |
Shards(分片) | 分表 | 顾名思义,当数据量太大单个节点都装不下的时候,就拆分到其它节点上 |
{ "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":系统标识 "cluster_name": "elasticsearch":Elasticsearch 集群的名称为 “elasticsearch”。 "cluster_uuid": "k61PBMDqTKO31rZeV-ENGA":Elasticsearch集群的唯一标识符。 "version":版本信息: "number": 版本号 "build_flavor": "default":构建的类型,这里是默认的。 "build_type": "tar":构建类型为 tar 包。 "build_hash": "93a57a1a76f556d8aee6a90d1a95b06187501310":构建的哈希值,用于唯一标识这个特定的构建。 "build_date": "2024-06-10T23:35:17.114581191Z":构建的日期和时间。 "build_snapshot": false:表示这个构建不是一个快照版本。 "lucene_version": "9.10.0":基于Lucene 9.10.0的版本。 "minimum_wire_compatibility_version": "7.17.0":最低兼容的网络传输版本。 "minimum_index_compatibility_version": "7.0.0":最低兼容的索引版本。 "tagline": "You Know, for Search":Elasticsearch 的标语,说明其用途是进行搜索。
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "zs_index"
}
"acknowledged": true:指示请求是否被成功接受和处理。
"shards_acknowledged": true:指示所有分片是否已经确认请求。
"index": "zs_index":这表示操作涉及的索引名称为 “zs_index”。
{ "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":这个对象包含了发生的错误信息。 "root_cause":根本原因的数组,指示导致问题的具体原因。 "type": "resource_already_exists_exception":错误的类型,表示尝试创建的索引已经存在。 "reason": "index [zs_index/dCMAgdlqTeaihB4JSH1gNw] already exists":错误的详细原因,指明索引 “zs_index” 和其唯一标识符 “dCMAgdlqTeaihB4JSH1gNw” 已经存在。 "index_uuid": "dCMAgdlqTeaihB4JSH1gNw":已存在索引的 UUID。 "index": "zs_index":已存在索引的名称。 "type": "resource_already_exists_exception":总体错误类型,与根本原因相同。 "reason": "index [zs_index/dCMAgdlqTeaihB4JSH1gNw] already exists":再次指明索引已经存在的原因。 "index_uuid": "dCMAgdlqTeaihB4JSH1gNw":重复指定已存在索引的 UUID。 "index": "zs_index":重复指定已存在索引的名称。 "status": 400:HTTP 状态码,表示客户端请求错误
{ "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": {}:索引的别名列表为空,表示该索引当前没有别名。 "mappings": {}:索引的映射为空对象,即没有定义特定的字段映射。 "settings":索引的设置信息: "index": "routing": "allocation": "include": "_tier_preference": "data_content":指定索引分配时偏好的数据内容层级。 "number_of_shards": "1":该索引被分成了一个分片。 "provided_name": "zs_index":索引的提供的名称为 “zs_index”。 "creation_date": "1719699272706":索引的创建日期的时间戳形式。 "number_of_replicas": "1":该索引有一个副本。 "uuid": "dCMAgdlqTeaihB4JSH1gNw":索引的唯一标识符 UUID。 "version": "created": "8505000":索引的版本信息,表示索引在 Elasticsearch 版本 “8505000” 中创建。
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: 索引的健康状态,此处为 “yellow”,表示所有预期的分片都可用,但副本尚未分配。
status: Elasticsearch 的状态指示符,这里是 “open”,表示索引是打开状态,可以接收读写操作。
index: 索引名。
uuid: 索引的唯一标识符。
pri: 主分片数为 1,即索引被分成了一个主分片。
rep: 副本数为 1,表示每个主分片有一个副本。
docs.count: 文档数量为 0,当前索引中的文档总数。
docs.deleted: 已删除的文档数量为 0。
store.size: 存储大小为 249b,索引占用的物理存储空间。
pri.store.size: 主分片的存储大小,也是 249b。
dataset.size: 数据集大小为 249b,即索引的数据集大小。
{
"acknowledged": true
}
返回true表示成功执行。
这是存入的数据 { "id":1, "content":"C是世界上最好的编程语言" } 这是返回的数据,若用户指定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中,每个文档都有一个唯一的ID,用于唯一标识和检索该文档。 "_version": 1: 表示该文档的版本号是1。每当文档被更新时,版本号会增加,这有助于跟踪文档的更改历史。 "result": "created": 表示操作的结果是创建了一个新的文档。 "_shards": 这个字段提供了关于索引操作的分片信息。 "total": 2: 表示总共有2个分片参与了这次索引操作(通常是一个主分片和其副本)。 "successful": 1: 表示有1个分片成功完成了索引操作。在yellow健康状态的索引中,这通常意味着主分片成功了,但副本分片可能还没有数据(因为它是yellow状态,副本可能还没有分配或同步)。 "failed": 0: 表示没有分片失败。 "_seq_no": 0: 是文档在Lucene段中的序列号,用于在内部跟踪文档的版本和顺序。 "_primary_term": 1: 主要术语(primary term)是与_seq_no一起使用的,用于确保文档版本的一致性,特别是在主节点更换时。
方式1,若有id号,再次执行增文档操作,可自动将create操作编程update操作。 更新数据 { "id":1, "content":"C是世界上最好的编程语言" } 方式2,请求内容同方式1 方式3,因为要修改局部数据,所以必须告知ES修改那块的局部数据,以下:第一层花括号和doc是固定格式。 { "doc" : { "content": "C是最好的编程语言" } } 3种方式的响应格式一致: { "_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: 表示该文档的版本号已更新为17。版本号在每次更新时增加,用于跟踪文档的变化历史。 "result": "updated": 表示更新操作已成功执行,文档被更新了。 "_shards": 提供了关于更新操作涉及的分片信息。 "total": 2: 表示总共有2个分片参与了更新操作(通常是一个主分片和其副本)。 "successful": 1: 表示有1个分片成功完成了更新操作。在yellow健康状态的索引中,这意味着主分片成功了,但副本分片可能尚未同步数据。 "failed": 0: 表示没有分片失败。 "_seq_no": 24: 是文档在Lucene段中的序列号,用于内部跟踪文档版本和顺序。 "_primary_term": 1: 主要术语(primary term)与_seq_no一起使用,确保文档版本的一致性,特别是在主节点更换时。
{ "_index": "zs_index", "_id": "1", "_version": 8, "_seq_no": 14, "_primary_term": 1, "found": true, "_source": { "id": 1, "content": "C是世界上最好的编程语言" } } "_seq_no": 14: 是文档在Lucene段中的序列号,用于内部跟踪文档版本和顺序。 "_primary_term": 1: 主要术语(primary term)与_seq_no一起使用,确保文档版本的一致性,尤其是在主节点更换时。 "found": true: 表示Elasticsearch成功找到了指定ID的文档,若为false,表示未找到。 "_source": 包含了文档的实际内容。
{ "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: 表示搜索操作耗费了137毫秒。 "timed_out": false: 表示搜索操作未超时。 "_shards": 提供了关于搜索操作涉及的分片信息。 "total": 1: 表示总共有1个分片参与了搜索操作。 "successful": 1: 表示所有参与的分片都成功完成了搜索。 "skipped": 0: 表示没有分片被跳过。 "failed": 0: 表示没有分片失败。 "hits": 包含了搜索结果的详细信息。 "total": {"value": 8, "relation": "eq"}: 表示符合搜索条件的文档总数为8个。 "value": 8: 具体的文档数。 "relation": "eq": 表示与总数值相等,即已经获取了所有匹配的文档。 "hits"数组: 包含了每个匹配文档的详细信息。 每个文档对象包括了: "_index": "zs_index": 文档所属的索引名称。 "_id": 文档的唯一ID。 "_score": 1: 文档的匹配分数,此处为1(最高分)。 "_source": 包含了文档的实际内容。
{ "_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": 提供了关于更新操作涉及的分片信息。 "total": 2: 表示总共有 2 个分片参与了更新操作(通常是一个主分片和其副本)。 "successful": 1: 表示有 1 个分片成功完成了更新操作。在索引状态为 yellow 时,这可能意味着主分片成功了,但副本分片可能尚未同步数据。 "failed": 0: 表示没有分片失败。 "_seq_no": 31: 是文档在 Lucene 段中的序列号,用于内部跟踪文档版本和顺序。 "_primary_term": 1: 主要术语(primary term)与 _seq_no 一起使用,确保文档版本的一致性,特别是在主节点更换时。
{ "query":{ "match": { "文档字段名":"要搜索的关键字" } } }
{ "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: 查询花费的时间,单位为毫秒。在这个例子中,值为8,表示查询执行花费了8毫秒时间。 timed_out: 表示查询是否超时。在这个例子中,值为false,表示查询未超时。 _shards: 分片相关信息,包括: total: 总分片数,这里是1个分片。 successful: 成功的分片数,这里是1个分片。 skipped: 被跳过的分片数,这里是0个分片。 failed: 失败的分片数,这里是0个分片。 hits: 查询命中的结果集信息,包含: total: 总命中数,这里是6。 max_score: 结果集中最高得分,这里是0.074107975。 hits: 包含具体的命中文档数组。 每个文档包含以下信息: _index: 文档所在的索引。 _id: 文档的唯一标识符。 _score: 文档的得分。 _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)之意。
{ "query": { "bool": { "must": [ { "match": { "content": "C语言" } }, { "match": { "content": "C++语言" } } ], "filter": { "range": { "content": { "gt": 1 } } } } } }
响应结果同上。
{ "query":{ "match_phrase" :{ "字段名":"要搜索的关键字" } } }
{ "query":{ "match_phrase" :{ "字段名":"要搜索的关键字" } }, "highlight":{ "fields":{ "字段名":{} } } }
{ "aggs" : { "id_group_avg" : { "avg" : { "field" : "字段名" } } }, "size":0 }
{ "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: 查询花费的时间,单位是毫秒。这里是 35 毫秒。 timed_out: 查询是否超时。这里显示为 false,表示查询在规定时间内完成。 _shards: 这个对象提供关于查询在分片上的执行情况的详细信息: total: 总分片数。 successful: 成功完成查询的分片数。 skipped: 跳过的分片数。 failed: 查询失败的分片数。 在这个例子中,总分片数为 1,且成功完成了查询。 hits: 包含有关查询匹配的文档信息: total: 文档匹配的总数。 value: 匹配的文档数,这里是 6。 relation: 匹配关系,这里是 “eq” 表示精确匹配。 max_score: 最高得分,如果不需要计算得分则为 null。 hits: 实际匹配的文档数组。在这个例子中是空的,因为没有具体的文档数据。 aggregations: 聚合结果信息: id_group_avg: 聚合名称,这里的值为 1。具体的聚合结果会根据你的查询和聚合定义而有所不同。
这块由于涉及到字段的改动,所以需要重新建立索引,并且添加了映射(mapping)的概念
重新建立一个people索引 PUT请求 IP:9200/people 再次请求,添加映射 IP:9200/people/_mapping { "properties" :{ "name" : { "type":"text", "index":true }, "sex" : { "type":"keyword", "index":true }, "tel" : { "type":"keyword", "index":false } } } 上方的index指的是是否为这条数据添加索引。 type是索引类型,text代表支持分词查询(MySQL like '%kw%'),keyword代表不可分词查询 (MySQL = 'kw')。 然后添加三条数据 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" : "男" 把性去掉,搜索不到数据 } } } GET IP:9200/people/_search { "query" :{ "match" :{ "name" : "张" 把三去掉,可以搜索到数据 } } } GET IP:9200/people/_search { "query" :{ "match" :{ "tel" : "188" 若输入手机号前3位,则搜不到数据,输入完整的手机号,则可以搜索到数据 } } }
官方文档:https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/getting-started-php.html#_installation
某些ES Api(例如创建索引)不能重复执行,重复执行会报错,所以在执行写操作的上游做判断,或者使用try catch。
composer require elasticsearch/elasticsearch
推荐安装symfony/var-dumper,用于dd()或dump()执行,美化输出。
新建PHP文件,以下代码数据为公共部分。
include './vendor/autoload.php';
use Elastic\Elasticsearch\ClientBuilder;
//连接ES
$client = ClientBuilder::create()->setHosts(['192.168.0.183:9200'])->build();
//若es有密码,则需要添加一个setBasicAuthentication()方法。
$client = ClientBuilder::create()->setHosts(['192.168.0.183:9200'])->setBasicAuthentication('elastic', '123456')->build();
返回bool
$response = $client->indices()->create([
'index' => 'php_index'
]);
$response->asBool();
返回bool
$response = $client->indices()->exists(['index' => 'php_index']);
dd($response->asBool());
返回array
$response = $client->indices()->get(['index' => 'php_index']);
dd($response->asArray());
返回bool
$response = $client->indices()->delete(['index' => 'php_index']);
dd($response->asBool());
返回bool
$params = [
'index' => 'php_index',
'body' => [
'properties' => [
'name' => [
'type' => 'text',
],
]
]
];
$response = $client->indices()->putMapping($params);
dd($response->asBool());
返回bool $params = [ 'index' => 'php_index', 'body' => [ 'mappings' => [ 'properties' => [ 'title' => [ 'type' => 'text', ], 'content' => [ 'type' => 'text', ], ] ] ] ]; $response = $client->indices()->create($params); dd($response->asBool());
返回数组
$response = $client->indices()->getMapping();
dd($response->asArray());
返回数组
$response = $client->indices()->getMapping(['index' => 'php_index']);
dd($response->asArray());
准备四个直辖市的名称,简介,人口和面积大小。 $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());
返回bool $params = [ 'index' => 'php_index', 'id' => 1, 'body' => [ 'id' => 1, 'city' => '北京市', 'description' => '北京市(Beijing),简称“京”,古称燕京、北平,是中华人民共和国首都、直辖市、国家中心城市、超大城市, 国务院批复确定的中国政治中心、文化中心、国际交往中心、科技创新中心, 中国历史文化名城和古都之一,世界一线城市', 'population' => '2186', 'area' => '16411', ] ]; $response = $client->index($params); dd($response->asBool()); 再增加3条数据 $params = [ 'index' => 'php_index', 'id' => 2, 'body' => [ 'id' => 2, 'city' => '上海市', 'description' => '上海市(Shanghai City),简称“沪” ,别称“申”,中华人民共和国直辖市、国家中心城市、超大城市、上海大都市圈核心城市、国家历史文化名城 [206],是中国共产党的诞生地。上海市入围世界Alpha+城市, 基本建成国际经济、金融、贸易、航运中心,形成具有全球影响力的科技创新中心基本框架。截至2022年12月底,上海市辖16个区,107个街道、106个镇、2个乡。', 'population' => '2487', 'area' => '6341', ] ]; $params = [ 'index' => 'php_index', 'id' => 3, 'body' => [ 'id' => 3, 'city' => '天津市', 'description' => '天津市(Tianjin City),简称“津”,别称津沽、津门,是中华人民共和国省级行政区、直辖市、国家中心城市、超大城市 [222],地处中华人民共和国华北地区,海河流域下游,东临渤海,北依燕山,西靠首都北京市,其余均与河北省相邻。截至2023年10月,天津市共辖16个区。', 'population' => '1364', 'area' => '11966', ] ]; $params = [ 'index' => 'php_index', 'id' => 4, 'body' => [ 'id' => 4, 'city' => '重庆市', 'description' => '重庆市,简称“渝”, 别称山城、江城,是中华人民共和国直辖市、国家中心城市、超大城市,国务院批复的国家重要中心城市之一、长江上游地区经济中心, 国际消费中心城市,全国先进制造业基地、西部金融中心、西部科技创新中心、 国际性综合交通枢纽城市和对外开放门户,辖38个区县', 'population' => '3191', 'area' => '82400', ] ];
返回数组 //假设MySQL查询出来的数据如下 $mysql_data = [ [ 'id' => 1024, 'city' => 'xx市', 'description' => 'xxxx', 'population' => '6666', 'area' => '6666', ], [ 'id' => 1025, 'city' => 'yy市', 'description' => 'yyyy', 'population' => '8888', 'area' => '8888', ] ]; //由于ES插入的要求,需要将插入数据的格式转化,为此可以封装一个方法 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()); 可根据返回的数据再次循环,排查失败掉的漏网之鱼
返回bool
$params = [
'index' => 'php_index',
'id' => '1025'
];
$response = $client->delete($params);
dd($response->asBool());
方式1: 返回mixed for($i = 1000; $i < 1050; $i++) { //模拟要删除这些数据 $params = [ 'index' => 'php_index', 'id' => $i ]; if(! $client->exists($params)->asBool()) { continue; } $response = $client->delete($params)->asBool(); if(! $response) { //若删除失败,请添加其它操作,记录日志或存入队列,进行重试或者人工介入 } } 方式2: 返回mixed for($i = 1000; $i < 1050; $i++) { //模拟要删除这些数据 $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)) { //若删除失败,请添加其它操作,记录日志或存入队列,进行重试或者人工介入 } } } else { echo "批量删除成功!"; }
返回bool $params = [ 'index' => 'php_index', 'id' => 1, 'body' => [ 'script' => [ 'source' => 'ctx._source.remove(params.field)', 'params' => [ 'field' => '要删除的字段名' ] ] ] ]; $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 官方文档演示有误,请按照以下正确写法。 $params = [ 'index' => 'php_index', 'id' => 1, 'body' => [ 'script' => [ //表达式 'source' => 'ctx._source.population += params.population', //给北京人口加4万,population为自定义文档字段,其余字符固定写法。 //表达式所使用的变量 'params' => [ 'population' => 4 ], ], ] ]; $response = $client->update($params); dd($response->asBool());
$params = [
'index' => 'php_index',
'id' => 60, //若id对应的文档不存在,则利用upsert段的数据,重新生成一个id为60的文档。
'body' => [
'doc' => [
'city' => '台北市'
],
'upsert' => [
'append_field' => 1
],
]
];
$response = $client->update($params);
dd($response->asBool());
//假设以下数据时数据表中查询出来的字段,要修改以下内容 $mysql_data = [ ['id' => 1, 'city' => '北京'], ['id' => 2, 'city' => '上海'], ]; //可以封装一个方法,格式化数据 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)) { //若删除失败,请添加其它操作,记录日志或存入队列,进行重试或者人工介入 } } } 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' => '要删除的字段名' ] ] ] ]; $response = $client->update($params); dd($response->asBool());
查询关键词官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/term-level-queries.html
返回string $params = [ 'index' => 'php_index', 'id' => 1, ]; $response = $client->get($params); echo $response->asString(); 得到以下结果 { "_index": "php_index", "_id": "1", "_version": 1, "_seq_no": 0, "_primary_term": 1, "found": true, "_source": { "id": 1, "city": "北京市", "description": "北京市(Beijing),简称“京”,古称燕京、北平,是中华人民共和国首都、直辖市、国家中心城市、超大城市, 国务院批复确定的中国政治中心、文化中心、国际交往中心、科技创新中心, 中国历史文化名城和古都之一,世界一线城市", "population": "2186", "area": "16411" } }
返回array
$response['hits']['total']['value']可获取条数
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'match_all' => new StdClass
]
]
];
$response = $client->search($params);
dd($response->asArray());
返回数组
$response['hits']['total']['value']可获取条数
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'ids' => [
'values' => [1, 2]
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
返回数组 //传输的页码 $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());
返回数组
$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);
返回int
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'match_all' => new StdClass
]
]
];
$response = $client->count($params);
dd($response->asArray()['count'] ?? 0);
返回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()); 返回格式如下,具体要用那个字段,看具体需求 <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),简称“京”,古称燕京、北平,是中华人民共和国首都、直辖市、国家中心城市、超大城市, 国务院批复确定的中国政治中心、文化中心、国际交往中心、科技创新中心, 中国历史文化名城和古都之一,世界一线城市", "population":2198, "area":"16411", "new_field":"new_value" }, "highlight":{ "description":["<em>北</em><em>京</em>市(Beijing),简称“<em>京</em>”,古称燕<em>京</em>、<em>北</em>平,是中华人民共和国首都、直辖市、国家中心城市、超大城市, 国务院批复确定的中国政治中心、文化中心、国际交往中心、科技创新中心, 中国历史文化名城和古都之一"] } }, { "_index":"php_index", "_id":"3", "_score":2.5460577, "_source":{ "id":3, "city":"天津市", "description":"天津市(Tianjin City),简称“津”,别称津沽、津门,是中华人民共和国省级行政区、直辖市、国家中心城市、超大城市 [222],地处中华人民共和国华北地区,海河流域下游,东临渤海,北依燕山,西靠首都北京市,其余均与河北省相邻。截至2023年10月,天津市共辖16个区。", "population":"1364", "area":"11966" }, "highlight":{ "description":["天津市(Tianjin City),简称“津”,别称津沽、津门,是中华人民共和国省级行政区、直辖市、国家中心城市、超大城市 [222],地处中华人民共和国华<em>北</em>地区,海河流域下游,东临渤海,<em>北</em>依燕山,西靠首都<em>北</em><em>京</em>市",",其余均与河<em>北</em>省相邻。"] } } ] } }
返回array
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'match_all' => new stdClass
],
'from' => 0,
'size' => 1,
]
];
$response = $client->search($params);
dd($response->asArray());
方式1 针对integer字段的精准匹配
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'term' => [
'city' => '北京市' //北京或北或京无法查询出指定数据
]
]
]
];
$response = $client->search($params);
dd($response->asArray());
方式1 返回array 这种方式仅支持text类型 $params = [ 'index' => 'php_index', 'body' => [ 'query' => [ 'match' => [ 'description' => '北京' ] ] ] ]; $response = $client->search($params); dd($response->asArray()); 方式2 返回array 非text类型,可手动分词 $params = [ 'index' => 'php_index', 'body' => [ 'query' => [ 'bool' => [ 'should' => [ //or [ 'match' => ['city' => '北京'] ], [ 'match' => ['city' => '北京市'] ] ], 'minimum_should_match' => 1 //minimum_should_match 设置为 1,表示至少需要匹配一个 should 子句中的条件 ] ] ] ]; $response = $client->search($params); dd($response->asArray());
方式1,针对keyword mapping 返回array $params = [ 'index' => 'php_index', 'body' => [ 'query' => [ 'wildcard' => [ 'city' => '*北京*' //*表示任意字符,?表示任意一个字符 ] ] ] ]; $response = $client->search($params); dd($response->asArray()); 方式2,针对text mapping,并非严格意义上的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());
返回array
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'prefix' => [
'city' => '北'
]
]
]
];
$response = $client->search($params);
$params = [
'index' => 'php_index',
'body' => [
'query' => [
'wildcard' => [
'city' => '*京市'
]
]
]
];
$response = $client->search($params);
返回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平方千米以内的城市数据 'gt' => 1000, 'lt' => 10000, ] ] ] ] ]; $response = $client->search($params); dd($response->asArray());
$params = [ 'index' => 'php_index', 'body' => [ 'query' => [ 'regexp' => [ 'city' => '.*北京.*' //搜索包含北京关键字的字段 ] ] ] ]; $response = $client->search($params); dd($response->asArray()); .*: 匹配任意数量的任意字符 .: 匹配任意单个字符。 *: 匹配前面的元素零次或多次。 +: 匹配前面的元素一次或多次。 ?: 匹配前面的元素零次或一次。 ^: 匹配字符串的开头。 $: 匹配字符串的结尾。 [...]: 匹配方括号中的任意字符。 {n}: 匹配前面的元素恰好 n 次。 {n,}: 匹配前面的元素至少 n 次。 {n,m}: 匹配前面的元素至少 n 次,但不超过 m 次。
返回bool $params = [ 'index' => 'php_index', 'body' => [ 'query' => [ 'bool' => [ 'must_not' => [ 'term' => [ 'city' => '北京市' //返回不是北京市的数据 ] ] ] ] ] ]; $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());
返回array $params = [ 'index' => 'php_index', 'body' => [ 'query' => [ 'bool' => [ 'must' => [ //返回city字段是北京市,并且描述带有首都的数据 ['term' => ['city' => '北京市']], ['match' => ['description' => '首都']], ] ] ] ] ]; $response = $client->search($params); dd($response->asArray());
返回array $params = [ 'index' => 'php_index', 'body' => [ 'query' => [ 'bool' => [ 'should' => [ //查询城市名北京市,或者描述含有沪的描述内容 ['term' => ['city' => '北京市']], ['match' => ['description' => '沪']], ] ] ] ] ]; $response = $client->search($params); dd($response->asArray());
$params = [ 'index' => 'php_index', 'body' => [ 'query' => [ 'bool' => [ //查询城市名为北京市或上海市,并且描述带有京字的数据 'must' => [ [ 'bool' => [ 'should' => [ ['term' => ['city' => '北京市']], ['term' => ['city' => '上海市']] ] ] ], ['match' => ['description' => '京']] ] ] ] ] ]; $response = $client->search($params); dd($response->asArray());
单字段排序 $params = [ 'index' => 'php_index', 'body' => [ 'query' => [ 'match_all' => new StdClass, ], 'sort' => [ //四个直辖市数据按照区域大小排名 ['area' => ['order' => 'asc']] //asc或desc ] ] ]; $response = $client->search($params); dd($response->asArray()); 多字段排序 $params = [ 'index' => 'php_index', 'body' => [ 'query' => [ 'match_all' => new StdClass, ], 'sort' => [ //区域按照降序,人口按照升序排,条件不会冲突,回想MySQL order by那样,合并处理。 ['area' => ['order' => 'asc']], //asc或desc ['population' => ['order' => 'desc']], //asc或desc ] ] ];
返回bool $params = [ 'index' => 'php_index', 'body' => [ 'size' => 0, // 设置为0表示不返回实际的文档,仅返回聚合结果 'aggs' => [ 'population_data' => [ //这个key为自定义名称 'avg' => [ //返回4个直辖市平均人口 'field' => 'population' ] ] ] ] ]; $response = $client->search($params); dd($response->asArray()); avg : 平均值 sum :总和 min : 最小值 max :最大值 没有count。
返回string $params = [ 'index' => 'php_index', 'body' => [ 'size' => 0, // 不返回文档,只返回聚合结果 'aggs' => [ 'city_group' => [ //自定义名称 'terms' => [ 'field' => 'city', 'size' => 10 // 聚合结果的数量限制 ] ] ] ] ]; $response = $client->search($params)->asArray(); $aggregations = $response['aggregations']['city_group']['buckets']; foreach ($aggregations as $bucket) { echo "城市名:" . $bucket['key'] . " - 本组组对应的数量:" . $bucket['doc_count'] . "\n"; } 城市名:上海市 - 本组组对应的数量:1 城市名:北京市 - 本组组对应的数量:1 城市名:天津市 - 本组组对应的数量:1 城市名:重庆市 - 本组组对应的数量:1
返回array 个人还是推荐使用自定义字段,因为['hits']['_score']字段得出来分数不可控。 搜索城市,原先是北京靠前,现在通过修改权重,使其上海靠前 $params = [ 'index' => 'php_index', 'body' => [ 'query' => [ 'function_score' => [ 'query' => [ 'bool' => [ 'should' => [ ['term' => ['city' => '北京市']], ['match' => ['description' => '沪']] ] ] ], 'functions' => [ [ 'filter' => [ 'match' => ['description' => '沪'] ], 'weight' => 2 // 增加包含“沪”的文档的权重 ] ], 'boost_mode' => 'sum' ] ], 'sort' => [ '_score' => [ 'order' => 'desc' // 按照得分降序排序 ] ] ] ]; $response = $client->search($params); dd($response->asArray()); boost_mode设定了如何将查询的基础得分(由 query 部分确定)与功能得分(由 functions 部分计算)进行组合。以下是几种常用的 boost_mode 设置: multiply: 基础得分与功能得分相乘。 replace: 功能得分替代基础得分。 sum: 基础得分与功能得分相加。 avg: 基础得分与功能得分的平均值。 max: 取基础得分与功能得分中的最大值。
//counter子对岸自增
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;
}
关闭ES
执行以下代码,注意版本号的问题
bin/elasticsearch-plugin install https://get.infini.cloud/elasticsearch/analysis-ik/8.14.1
进入交互界面输入Y。
之后启动ES
演示分词: GET IP:9200/_analyze 传入以下内容 { "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 } ] }
有些场景,有很多的专业用语,但是IK分词器把它拆分开,就显得不是很精准,因此可以添加自定义分词解决。
vim ES安装目录/config/analysis-ik/IKAnalyzer.cfg.xml
在<entry key="ext_dict"></entry>的双标签中间写入文件名,例如
<entry key="ext_dict">self_words.dic</entry>
vim self_words.dic
逐行添加自定义词汇
重启ES。
返回bool $params = [ 'index' => 'test_index', 'body' => [ 'settings' => [ 'analysis' => [ 'analyzer' => [ 'analyzer_ik_max_word' => [ 'type' => 'ik_max_word' //ik分词器内置关键配置,更多的分词结果 ], 'analyzer_ik_smart' => [ 'type' => 'ik_smart' //ik分词器内置关键配置,更快的分词结果 ] ] ] ], 'mappings' => [ 'properties' => [ 'content' => [ 'type' => 'text', 'analyzer' => 'analyzer_ik_smart', // 设置索引时的分词器 'search_analyzer' => 'analyzer_ik_smart' // 设置搜索时的分词器 ] ] ] ] ]; $response = $client->indices()->delete(['index' => 'test_index']); dump($response->asBool());
返回bool 这里尝试创建了一个更复杂的索引,添加了过滤器,但是不生效,不知道是那里的问题。 如下,按照以下索引的配置,过滤后的结果,应当是"C世界上最好编程语言",然后再分词,可却不生效。 GET IP:9200/test_index/_analyze { "analyzer":"self_ik_max_word", "text" : "PHP是世界上最好的编程语言" } $params = [ 'index' => 'test_index', // 指定要创建的索引名称 'body' => [ 'settings' => [ // 配置索引的设置 'analysis' => [ // 分析器设置 'char_filter' => [ // 字符过滤器设置 'self_char_filter' => [ // 自定义字符过滤器名称 'type' => 'mapping', // 过滤器类型为映射 'mappings' => ['PHP => C'] // 替换分词的字符 ] ], 'filter' => [ // 过滤器设置 'self_filter' => [ // 自定义停用词过滤器名称 'type' => 'stop', // 过滤器类型为停用词 'stopwords' => ['是', '的'] // 停用词列表 ] ], 'analyzer' => [ // 分析器设置 'self_ik_max_word' => [ // IK 分词器名称 'type' => 'ik_max_word', // 使用 IK 分词器的最大分词模式 'char_filter' => ['html_strip', 'self_char_filter'], // html_strip过滤器会把html标签忽略,但html转义字符仍旧生效( 仍旧是空格),且会把<br/>转化为\n 'filter' => ['lowercase', 'self_filter'] //lowercase过滤器是将大写字母变为小写 ], 'self_ik_smart' => [ // IK 分词器名称 'type' => 'ik_smart', // 使用 IK 分词器的快速分词模式 'char_filter' => ['html_strip', 'self_char_filter'], // html_strip过滤器会把html标签忽略,但html转义字符仍旧生效( 仍旧是空格),且会把<br/>转化为\n 'filter' => ['lowercase', 'self_filter'] //lowercase过滤器是将大写字母变为小写 ] ] ] ], 'mappings' => [ // 配置索引的映射 'properties' => [ // 文档字段的属性设置 'content' => [ // 文档中的字段名称 'type' => 'text', // 字段类型为文本 'analyzer' => 'self_ik_max_word', // 设置索引时的分词器 'search_analyzer' => 'self_ik_max_word' // 设置搜索时的分词器 ] ] ] ] ]; $response = $client->indices()->create($params); dd($response->asBool());
保证ES服务已启动。 防火墙开启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 权限配置 chown -R es:es kibana-8.14.1 切换用户 su es kibana不支持elastic用户,所以需要创建新用户,并赋予超级管理员角色,并赋予kibana_system角色 elasticsearch-users useradd zs elasticsearch-users roles -a superuser zs 少了这一步报错,让我搞了4个小时。 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" 启动 kibana-8.14.1/bin/kibana 过2分钟后,访问http://IP:5601
背景:先创建一个num_test索引,并添加名为num的int类型的映射。并插入一条数据。 流程:当进行数据更新时,先做一次查询(get方法,不是search方法),获取相关的_primary_term,_seq_no值。 当更新数据时,添加对应的版本号,如果ES检测到版本号不对,则会报错,如下: $params = [ 'index' => 'num_test', 'id' => 1, 'body' => [ 'doc' => [ 'num' => 10 ] ], 'if_seq_no' => 3, // 使用序列号 'if_primary_term' => 1, // 使用主分片术语 ]; try { $response = $client->update($params); } catch (\Exception $exception) { echo '出错了,这里重试查询后再更新,或者记录错误等其它操作。。。' }
$params = [ 'index' => 'num_test', 'id' => 1, 'body' => [ 'doc' => [ 'num' => 1800 ] ], 'version' => 40, // 提供外部版本号 'version_type' => 'external' // 使用外部版本号 ]; try { $response = $client->update($params); //版本不生效的方案,不推荐使用 } catch (\Exception $exception) { dump('出错了,这里进行重试,或者记录错误,等其它操作'); }
$params = [ 'index' => 'index', 'id' => '10', 'body' => [ 'doc' => [ 'field1' => 'new value1', 'field2' => 'new value2' ] ], 'retry_on_conflict' => 3 // 设置重试次数 ]; try { $response = $client->update($params); } catch (Exception $e) { // 处理异常,可以选择记录日志或执行其它操作,这个catch是用来重试3次还报错的兜底策略。 }
POST IP:9200/_sql?format=json //类型可未txt,用制表符更直观的展示 { "query": "SELECT * FROM php_index WHERE city = '北京市'" } 结果: { "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),简称“京”,古称燕京、北平,是中华人民共和国首都、直辖市、国家中心城市、超大城市, 国务院批复确定的中国政治中心、文化中心、国际交往中心、科技创新中心, 中国历史文化名城和古都之一,世界一线城市", 1, 2186 ] ] }
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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。