7.2批量插入
POST _bulk { "create" : { "_index" : "taibai", "_id" : "3" } } {"id":2002,"name":"name1","age": 20,"sex": "男"} { "create" : { "_index" : "taibai", "_id" : "4" } } {"id":2003,"name":"name1","age": 20,"sex": "男"} 1
7.3批量删除
POST _bulk { "delete" : { "_index" : "taibai", "_id" : "8PiK3W0BdTjVHQ-cxHs1" } } { "delete" : { "_index" : "taibai", "_id" : "6vh43W0BdTjVHQ-cHXv8" } }
7.4批量修改
POST _bulk { "update" : {"_id" : "4", "_index" : "taibai"} } { "doc" : {"name" : "太白"} } { "update" : {"_id" : "3", "_index" : "taibai"} } { "doc" : {"name" : "太白"} }
8.分页查询
GET /taibai/_search?size=1&from=2 size: 结果数,默认10 from: 跳过开始的结果数,默认0
分页一
浅分页,它的原理很简单,就是查询前20条数据,然后截断前10条,只返回10-20的数据。这样其实白白浪费了前10条的查询
GET /bank/_search { "sort": [ { "age": { "order": "desc" } } ], "size": 1000, "from": 0 }
分页二
scroll 深分页,使用scroll,每次只能获取一页的内容,然后会返回一个scroll_id。根据返回的这个scroll_id可以不断地获取下一页的内容,所以scroll并不适用于有跳页的情景
scroll=5m表示设置scroll_id保留5分钟可用。
使用scroll必须要将from设置为0。
size决定后面每次调用_search搜索返回的数量
GET /bank/_search?scroll=5m { "size": 20, "from": 0, "sort": [ { "_id": { "order": "desc" } } ] }
会返回一个:
"_scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAB9AWTVIyY1pKcmhUT0dBT1FXLU5ueHdDQQ==" 以后调用: GET _search/scroll { "scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAABMIWTVIyY1pKcmhUT0dBT1FXLU5ueHdDQQ==", "scroll": "5m" }
删除scroll_id
DELETE _search/scroll/DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAABMIWTVIyY1pKcmhUT0dBT1FXLU5ueHdDQQ==
删除所有scroll_id
DELETE _search/scroll/_all
注意:根据官方文档的说法,scroll是非常消耗资源的,所以一个建议就是当不需要了scroll数据的时候,尽可能快的把scroll_id显式删除掉。scroll 的方式,官方的建议不用于实时的请求(一般用于数据导出),因为每一个 scroll_id 不仅会占用大量的资源,而且会生成历史快照,对于数据的变更不会反映到快照上。
分页三
search_after 深分页,是根据上一页的最后一条数据来确定下一页的位置,同时在分页请求的过程中,如果有索引数据的增删改查,这些变更也会实时的反映到游标上。但是需要注意,因为每一页的数据依赖于上一页最后一条数据,所以无法跳页请求。为了找到每一页最后一条数据,每个文档必须有一个全局唯一值,官方推荐使用 _uid 作为全局唯一值,其实使用业务层的 id 也可以。使用search_after必须要设置from=0。
GET /bank/_search { "size": 20, "from": 0, "sort": [ { "_id": { "order": "desc" } } ] }
拿到返回最后一条数据的_id
GET /bank/_search { "size": 20, "from": 0, "sort": [ { "_id": { "order": "desc" } } ], "search_after": [ 980 ] }
9.映射
前面我们创建的索引以及插入数据,都是由Elasticsearch进行自动判断类型,有些时候我们是需要进行明确字段类型的,否则,自动判断的类型和实际需求是不相符的。
自动判断的规则如下:
JSON type Field type Boolean: true or false “boolean” Whole number: 123 “long” Floating point: 123.45 “double” String, valid date: “2014-09-15” “date” String: “foo bar” “string”
创建明确类型的索引:
PUT /goods { "settings": { "number_of_replicas": 0, "number_of_shards": 1 }, "mappings": { "properties": { "id": { "type": "long" }, "sn": { "type": "keyword" }, "name": { "type": "text", "analyzer": "ik_max_word" }, "price": { "type": "double" }, "num": { "type": "integer" }, "alert_num": { "type": "integer" }, "image": { "type": "keyword" }, "images": { "type": "keyword" }, "weight": { "type": "double" }, "create_time": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss" }, "update_time": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss" }, "spu_id": { "type": "keyword" }, "category_id": { "type": "integer" }, "category_name": { "type": "text", "analyzer": "ik_smart" }, "brand_name": { "type": "keyword" }, "spec": { "type": "text", "analyzer": "ik_max_word" }, "sale_num": { "type": "integer" }, "comment_num": { "type": "integer" }, "status": { "type": "integer" } } } }
添加一个字段到现有的映射
PUT /luban/_mapping { "properties": { "isold": { //字段名 "type": "keyword", //类型 "index": false } } }
更新字段的映射
除了支持的映射参数外,您不能更改现有字段的映射或字段类型。更改现有字段可能会使已经建立索引的数据无效。
如果您需要更改字段映射,创建具有正确映射一个新的索引和重新索引的数据转换成指数。
重命名字段会使在旧字段名称下已建立索引的数据无效。而是添加一个alias字段以创建备用字段名称。
查看索引的映射
GET /luban/_mapping
查看指定字段的映射信息
GET /luban/_mapping/field/name
10.结构化查询
10.1term查询
term 主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed 的字符串(未经分析的文本数据类型):
POST /taibai/_search { "query" : { "term" : { "age" : 20 } } }
10.2terms查询
terms 跟 term 有点类似,但 terms 允许指定多个匹配条件。 如果某个字段指定了多个值,那么文档需要一起去
做匹配:
POST /taibai/_search { "query" : { "terms" : { "age" : [20,27] } } }
10.3range查询
range 过滤允许我们按照指定范围查找一批数据:
gt :: 大于 gte :: 大于等于 lt :: 小于 lte :: 小于等于 POST /taibai/_search { "query": { "range": { "age": { "gte": 20, "lte": 22 } } } }
10.4exists查询
exists 查询可以用于查找文档中是否包含指定字段或没有某个字段,类似于SQL语句中的 IS_NULL 条件
包含这个字段就返回返回这条数据
POST /taibai/_search { "query": { "exists": { "field": "name" } } }
10.5 match查询
match 查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它。
如果你使用 match 查询一个全文本字段,它会在真正查询之前用分析器先分析 match 一下查询字符;如果用 match 下指定了一个确切值,在遇到数字,日期,布尔值或者 not_analyzed 的字符串时,它将为你搜索你
给定的值:
POST /taibai/_search { "query" : { "match" : { "name" : "三个小矮人" } } }
match查询会先对搜索词进行分词,分词完毕后再逐个对分词结果进行匹配,因此相比于term的精确搜索,match是分词匹配搜索
10.6 bool查询
bool 查询可以用来合并多个条件查询结果的布尔逻辑,它包含一下操作符:
must :: 多个查询条件的完全匹配,相当于 and 。
must_not :: 多个查询条件的相反匹配,相当于 not 。
should :: 至少有一个查询条件匹配, 相当于 or 。
这些参数可以分别继承一个查询条件或者一个查询条件的数组:
POST /taibai/_search { "query": { "bool": { "must": { "term": { "sex": "男" } }, "must_not": { "term": { "age": "29" } }, "should": [ { "term": { "sex": "男" } }, { "term": { "id": 1003 } } ] } } }
10.7过滤查询
查询年龄为20岁的用户。
POST /taibai/_search { "query": { "bool": { "filter": { "term": { "age": 20 } } } } }
批量导入测试数据
该数据是使用www.json- http://generator.com/生成的,因此请忽略数据的实际值和语义,因为它们都是随机生成的。您可以从这里下载示例数据集(accounts.json)。将其提取到当前目录,然后按如下方式将其加载到集群中:
curl -H "Content-Type: application/json" -XPOST "localhost:9200/bank/_bulk?pretty&refresh" --data-binary "@accounts.json"
官方文档练习案例:
1.给指定id加点年龄(age)
2.执行match_all操作,并按帐户余额降序对结果进行排序,并返回前10个
3.如何从搜索中返回两个字段,即帐号和余额
4.返回帐户为20的
5.返回地址中包含“mill”的所有帐户
6.返回地址中包含“mill”或“lane”的所有帐户
7.返回地址中包含“mill”和“lane”的所有帐户
8.地址中既不包含“mill”也不包含“lane”的所有帐户
9.返回所有40岁但不居住在ID的人(state不等于ID)的账户
10.使用bool查询返回余额在20000到30000之间的所有帐户,包括余额。换句话说,我们希望找到余额大于或等于20000,小于或等于30000的账户
11.按状态(state)对所有帐户进行分组,然后返回按count降序排列的前10个
12.按状态计算平均帐户余额(同样只针对按count降序排列的前10个状态)
13.基于之前(12)的聚合,我们现在按降序对平均余额排序
14.按照年龄等级(20-29岁,30-39岁,40-49岁)分组,然后按性别分组,最后得到每个年龄等级,每个性别的平均账户余额
POST /bank/_update/1 { "script": "ctx._source.age+=5" } GET /bank/_search { "query": { "match_all": {} }, "sort": [ { "balance": { "order": "desc" } } ] } GET /bank/_search { "query": { "match_all": {} }, "_source": ["account_number","balance"] } GET /bank/_search { "query": { "match": { "account_number": "20" } } } GET /bank/_search { "query": { "match": { "address": "mill" } } } GET /bank/_search { "query": { "match": { "address": "mill lane" } } } GET /bank/_search { "query": { "bool": { "must": [ { "match": { "address": "mill" } }, { "match": { "address": "lane" } } ] } } } GET /bank/_search { "query": { "bool": { "must_not": [ { "match": { "address": "mill" } }, { "match": { "address": "lane" } } ] } } } GET /bank/_search { "query": { "bool": { "must": [ { "term": { "age": { "value": 40 } } } ], "must_not": [ { "match": { "state": "ID" } } ] } } } GET /bank/_search { "query": { "bool": { "must": [ { "range": { "balance": { "gte": 20000, "lte": 30000 } } } ] } } } GET /bank/_search { "aggs": { "status_group": { "terms": { "field": "state.keyword" } } }, "size": 0 } GET /bank/_search { "aggs": { "status_group": { "terms": { "field": "state.keyword" }, "aggs": { "balance_avg": { "avg": { "field": "balance" } } } } }, "size": 0 } GET /bank/_search { "aggs": { "status_group": { "terms": { "field": "state.keyword", "order": { "balance_avg": "asc" } }, "aggs": { "balance_avg": { "avg": { "field": "balance" } } } } }, "size": 0 } GET /bank/_search { "aggs": { "age_range": { "range": { "field": "age", "ranges": [ { "from": 20, "to": 30 },{ "from": 30, "to": 40 },{ "from": 40, "to": 50 } ] }, "aggs": { "gender_group": { "terms": { "field": "gender.keyword" }, "aggs": { "balance_avg": { "avg": { "field": "balance" } } } } } } }, "size": 0 }
6.中文分词
6.0 Analyzer 的组成
Character Filters (针对原始文本处理,例如,可以使用字符过滤器将印度阿拉伯数字( )转换为其等效的阿拉伯语-拉丁语(0123456789))
Tokenizer(按照规则切分为单词),将把文本 “Quick brown fox!” 转换成 terms [Quick, brown, fox!],tokenizer 还记录文本单词位置以及偏移量。
Token Filter(将切分的的单词进行加工、小写、刪除 stopwords,增加同义词)
6.1elasticsearch内置分词器
Standard 默认分词器 按词分类 小写处理
Simple 按照非字母切分,非字母则会被去除 小写处理
**Stop ** 小写处理 停用词过滤(the,a, is)
**Whitespace ** 按空格切分
**Keyword ** 不分词,当成一整个 term 输出
**Patter ** 通过正则表达式进行分词 默认是 \W+(非字母进行分隔)
**Language ** 提供了 30 多种常见语言的分词器
6.2分词api
POST /_analyze { "analyzer":"standard", "text":"tai bai" } POST /_analyze { "analyzer":"standard", "text":"决战到天亮" }
英文分词 一般以空格分隔,中文分词的难点在于,在汉语中没有明显的词汇分界点,如果分隔不正确就会造成歧义。
常用中文分词器,IK、jieba、THULAC等,推荐使用IK分词器。
6.3ik分词器安装
IK分词器 Elasticsearch插件地址:https://github.com/medcl/elasticsearch-analysis-ik
注意选择对应es的版本
1.下载项目 zip包
2.解压项目
3.进入项目跟目录 使用maven编译打包此项目
mvn clean mvn compile mvn package
4.执行完上面命令后 在{project_path}/elasticsearch-analysis-ik/target/releases/elasticsearch-analysis-ik-*.zip会有个zip,上传到linux elasticsearch 插件目录, 如: plugins/ik 注意在plugins下新建ik目录 将zip包上传到ik目录下
5.使用unzip命令解压zip包,没有unzip的 可先下载unzip 命令:yum install -y unzip zip
6.解压之后删除原来的zip包
7.检查是否需要修改版本信息
vim {path}/plugins/ik/plugin-descriptor.properties
8.重启 ik插件安装完成
9.测试中文分词器效果
POST /_analyze { "analyzer": "ik_max_word", 或者 //ik_smart "text": "决战到天亮" }
6.4拼音分词器
1.下载对应版本的zip包https://github.com/medcl/elasticsearch-analysis-pinyin/releases
2.可在Windows解压好,在plugins下创建pinyin文件夹
3.将解压内容放置在pinyin文件夹,重启
6.5自定义分词器
接受参数
tokenizer 一个内置的或定制的tokenizer。(必需) char_filter 一个可选的内置或自定义字符过滤器数组。 filter 一个可选的内置或定制token过滤器数组。 PUT my_index { "settings": { "analysis": { "analyzer": { "my_custom_analyzer": { "type": "custom", "tokenizer": "standard", "char_filter": [ "html_strip" //过滤HTML标签 ], "filter": [ "lowercase", //转小写 "asciifolding" //ASCII-折叠令牌过滤器 例如 à to a ] } } } } } POST my_index/_analyze { "analyzer": "my_custom_analyzer", "text": "Is this <b>déjà vu</b>?" }
创建一个中文+拼音的分词器(中文分词后拼音分词)
PUT my_index { "settings": { "analysis": { "analyzer": { "ik_pinyin_analyzer": { "type": "custom", "tokenizer": "ik_smart", "filter": [ "pinyin_max_word_filter" ] }, "ik_pingying_smark": { "type": "custom", "tokenizer": "ik_smart", "filter": [ "pinyin_smark_word_filter" ] } }, "filter": { "pinyin_max_word_filter": { "type": "pinyin", "keep_full_pinyin": "true", #分词全拼如雪花 分词xue,hua "keep_separate_first_letter": "true",#分词简写如雪花 分词xh "keep_joined_full_pinyin": true #分词会quanpin 连接 比如雪花分词 xuehua }, "pinyin_smark_word_filter": { "type": "pinyin", "keep_separate_first_letter": "false", #不分词简写如雪花 分词不分词xh "keep_first_letter": "false" #不分词单个首字母 如雪花 不分词 x,h } } } } } PUT /my_index/_mapping { "properties": { "productName": { "type": "text", "analyzer": "ik_pinyin_analyzer", #做文档所用的分词器 "search_analyzer":"ik_pingying_smark" #搜索使用的分词器 } } } POST /my_index/_doc { "productName": "雪花啤酒100L" } GET /my_index/_search { "query": { "match": { "productName": "雪Hua" } } }
7.全文搜索
7.1构建数据
PUT /test { "settings": { "index": { "number_of_shards": "1", "number_of_replicas": "0" } }, "mappings": { "properties": { "age": { "type": "integer" }, "email": { "type": "keyword" }, "name": { "type": "text" }, "hobby": { "type": "text", "analyzer": "ik_max_word" } } } } POST _bulk { "create" : { "_index" : "test","_id": "1000"} } {"name":"张三","age": 20,"mail": "111@qq.com","hobby":"羽毛球、乒乓球、足球"} { "create" : { "_index" : "test","_id": "1001"} } {"name":"李四","age": 21,"mail": "222@qq.com","hobby":"羽毛球、乒乓球、足球、篮球"} { "create" : { "_index" : "test","_id": "1002"} } {"name":"王五","age": 22,"mail": "333@qq.com","hobby":"羽毛球、篮球、游泳、听音乐"} { "create" : { "_index" : "test","_id": "1003"} } {"name":"赵六","age": 23,"mail": "444@qq.com","hobby":"跑步、游泳、篮球"} { "create" : { "_index" : "test","_id": "1004"} } {"name":"孙七","age": 24,"mail": "555@qq.com","hobby":"听音乐、看电影、羽毛球"}
7.2单词搜索
POST /test/_search { "query": { "match": { "hobby": "音乐" } }, "highlight": { "fields": { "hobby": {} } } }
7.3多词搜索
//搜索包含音乐和篮球的 POST /test/_search { "query": { "match": { "hobby": "音乐 篮球" } }, "highlight": { "fields": { "hobby": {} } } } //搜索包含音乐还有篮球的(and) POST /test/_search { "query": { "match": { "hobby": { "query": "音乐 篮球", "operator": "and" } } }, "highlight": { "fields": { "hobby": {} } } } GET /goods/_search { "query": { "bool": { "must": [ { "range": { "price": { "gte": 1000, "lte": 2000 } } }, { "match": { "name": "2018女鞋" } }, { "match": { "spec": "红色 黑色" } } ], "must_not": [ { "match": { "spec": "蓝色" } } ] } } } //在Elasticsearch中也支持这样的查询,通过minimum_should_match来指定匹配度,如:70%; POST /test/_search { "query": { "match": { "hobby": { "query": "游泳 羽毛球", "minimum_should_match": "70%" } } }, "highlight": { "fields": { "hobby": {} } } }
7.4组合搜索
//搜索结果中必须包含篮球,不能包含音乐,如果包含了游泳,那么它的相似度更高。 POST /test/_search { "query": { "bool": { "must": { "match": { "hobby": "篮球" } }, "must_not": { "match": { "hobby": "音乐" } }, "should": [{ "match": { "hobby": "游泳" } }] } }, "highlight": { "fields": { "hobby": {} } } } //默认情况下,should中的内容不是必须匹配的,如果查询语句中没有must,那么就会至少匹配其中一个。当然了, 也可以通过minimum_should_match参数进行控制,该值可以是数字也可以的百分比。 //minimum_should_match为2,意思是should中的三个词,至少要满足2个 POST /test/_search { "query": { "bool": { "should": [{ "match": { "hobby": "游泳" } }, { "match": { "hobby": "篮球" } }, { "match": { "hobby": "音乐" } } ], "minimum_should_match": 2 } }, "highlight": { "fields": { "hobby": {} } } }
7.5权重
搜索关键字为“游泳篮球”,如果结果中包含了“音乐”权重为10,包含了“跑步”权重为2。
POST /test/_search { "query": { "bool": { "must": { "match": { "hobby": { "query": "游泳篮球", "operator": "and" } } }, "should": [{ "match": { "hobby": { "query": "音乐", "boost": 10 } } }, { "match": { "hobby": { "query": "跑步", "boost": 2 } } } ] } }, "highlight": { "fields": { "hobby": {} } } }
8.Elasticsearch集群
192.168.204.209 elasticsearch.yml cluster.name: luban node.name: node-1 node.master: true node.data: true network.host: 0.0.0.0 http.port: 9200 #参数设置一系列符合主节点条件的节点的主机名或 IP 地址来引导启动集群。 cluster.initial_master_nodes: ["node-1"] # 设置新节点被启动时能够发现的主节点列表(主要用于不同网段机器连接) discovery.zen.ping.unicast.hosts: ["192.168.204.209","192.168.204.203","192.168.204.108"] # 该参数就是为了防止”脑裂”的产生。定义的是为了形成一个集群,有主节点资格并互相连接的节点的最小数目。 discovery.zen.minimum_master_nodes: 2 # 解决跨域问题配置 http.cors.enabled: true http.cors.allow-origin: "*"
192.168.204.203 elasticsearch.yml cluster.name: luban node.name: node-3 node.master: true node.data: true network.host: 0.0.0.0 http.port: 9200 cluster.initial_master_nodes: ["node-1"] discovery.zen.ping.unicast.hosts: ["192.168.204.209","192.168.204.203","192.168.204.108"] discovery.zen.minimum_master_nodes: 2 http.cors.enabled: true http.cors.allow-origin: "*"
192.168.204.108 elasticsearch.yml cluster.name: luban node.name: node-2 node.master: true node.data: true network.host: 0.0.0.0 http.port: 9200 cluster.initial_master_nodes: ["node-1"] discovery.zen.ping.unicast.hosts: ["192.168.204.209","192.168.204.203","192.168.204.108"] discovery.zen.minimum_master_nodes: 2 http.cors.enabled: true http.cors.allow-origin: "*"
启动后效果
一台机器搭建集群(一)
注意修改jvm.options
elasticsearch-7.3.2_node1 cluster.name: luban node.name: node-1 node.master: true node.data: true network.host: 0.0.0.0 http.port: 9200 transport.port: 9300 cluster.initial_master_nodes: ["node-1"] discovery.seed_hosts: ["192.168.204.209:9300", "192.168.204.209:9301","192.168.204.209:9302"] discovery.zen.minimum_master_nodes: 2 http.cors.enabled: true http.cors.allow-origin: "*"
elasticsearch-7.3.2_node2 cluster.name: luban node.name: node-2 node.master: true node.data: true network.host: 0.0.0.0 http.port: 9201 transport.port: 9301 cluster.initial_master_nodes: ["node-1"] discovery.seed_hosts: ["192.168.204.209:9300", "192.168.204.209:9301","192.168.204.209:9302"] discovery.zen.minimum_master_nodes: 2 http.cors.enabled: true http.cors.allow-origin: "*"
elasticsearch-7.3.2_node3 cluster.name: luban node.name: node-3 node.master: true node.data: true network.host: 0.0.0.0 http.port: 9202 transport.port: 9302 cluster.initial_master_nodes: ["node-1"] discovery.seed_hosts: ["192.168.204.209:9300", "192.168.204.209:9301","192.168.204.209:9302"] discovery.zen.minimum_master_nodes: 2 http.cors.enabled: true http.cors.allow-origin: "*"
分别启动:
./elasticsearch -p /tmp/elasticsearch_9200_pid -d ./elasticsearch -p /tmp/elasticsearch_9201_pid -d ./elasticsearch -p /tmp/elasticsearch_9202_pid -d
一台机器搭建集群(二)
新建目录:
注意赋予权限
chown -R taibai:taibai ES
分别启动:
./elasticsearch -d -E node.name=node-1 -E http.port=9200 -E transport.port=9300 -E path.data=/ES/data/node1 -E path.logs=/ES/logs/node1 ./elasticsearch -d -E node.name=node-2 -E http.port=9201 -E transport.port=9301 -E path.data=/ES/data/node2 -E path.logs=/ES/logs/node2 ./elasticsearch -d -E node.name=node-3 -E http.port=9202 -E transport.port=9302 -E path.data=/ES/data/node3 -E path.logs=/ES/logs/node3
https://blog.csdn.net/jiankunking/article/details/65448030
https://blog.csdn.net/lixiaohai_918/article/details/89569611
查看插件命令:./elasticsearch-plugin list
下载插件命令:./elasticsearch-plugin install analysis-icu
二、pdf版
【腾讯文档】ES课件完整版
https://docs.qq.com/pdf/DTm5rb2Z3UXNvRmtR
完成