1.写在前面
前面我已经介绍了elasticsearch的环境的搭建还有就是集群的环境的搭建,但是我们从来没有上手过对应的API,今天的博客我们来介绍下elasticsearch的常用的API以及elasticsearch的分词的策略,以及我们怎么安装我们的分词器。废话不多说,直接开始我们的博客吧。
2.常用的API
2.1创建空索引
PUT /king //索引的名称
{
"settings": {
"number_of_shards": "2", //分片数
"number_of_replicas": "0", //副本数
"write.wait_for_active_shards": 1 //写的活跃数,写的时候只有节点活跃数只有大于这个数,才能写入
}
}
2.2修改副本数
PUT king/_settings
{
"number_of_replicas" : "2"
}
2.3删除索引
DELETE /king
2.4插入数据
//指定id
POST /king/_doc/1001
{
"id":1001,
"name":"张三",
"age":20,
"sex":"男"
}
//不指定id es帮我们自动生成
POST /king/_doc
{
"id":1002,
"name":"三哥",
"age":20,
"sex":"男"
}
2.5更新数据
在Elasticsearch中,文档数据是不为修改的,但是可以通过覆盖的方式进行更新
PUT /king/_doc/1001
{
"id":1009,
"name":"李四",
"age":21,
"sex":"哈哈"
}
2.6局部更新
其实elasticsearch内部对partial update的实际执行和传统的全量替换方式是几乎一样的,其步骤如下:
- 内部先获取到对应的document;
- 将传递过来的field更新到document的json中(这一步实质上也是一样的);
- 将老的document标记为deleted(到一定时候才会物理删除);
- 将修改后的新的document创建出来
POST /king/_update/1001
{
"doc":{
"age":23
}
}
替换和更新的不同:替换是每次都会去替换,更新是有新的东西就更新,没有新的修改就不更新,更新比替换的性能好
2.7删除数据
DELETE /king/_doc/1001
2.8根据id搜索数据
GET /king/_doc/6_h43W0BdTjVHQ-cgnv2 //文档的id
2.9搜索全部数据
GET /king/_search 默认最多返回10条数据
POST /bank/_search
{
"query": { "match_all": {} },
"sort": [
{
"属性名": {
"order": "asc"
}
}
]
}
返回的结果的情况的解释
结果参数 | 解释 |
---|---|
took | Elasticsearch运行查询需要多长时间(以毫秒为单位) |
timed_out | 搜索请求是否超时 |
_shards | 搜索了多少碎片,并对多少碎片成功、失败或跳过进行了细分。 |
max_score | 找到最相关的文档的得分 |
hits.total.value | 找到了多少匹配的文档 |
hits.sort | 文档的排序位置(当不根据相关性得分排序时) |
hits._score | 文档的相关性评分(在使用match_all时不适用) |
2.10关键字搜索数据
GET /king/_search?q=age:23 //查询年龄等于23的
2.11DSL搜索
POST /king/_search
{
"query" : {
"match" : { //查询年龄等于23的
"age" : 23
}
}
}
//查询地址等于mill或者lane
GET /bank/_search
{
"query": { "match": { "address": "mill lane" } }
}
//查询地址等于(mill lane)的
GET /bank/_search
{
"query": { "match_phrase": { "address": "mill lane" } }
}
//注意:match 中如果加空格,那么会被认为两个单词,包含任意一个单词将被查询到
//match_parase 将忽略空格,将该字符认为一个整体,会在索引中匹配包含这个整体的文档。
POST /king/_search //查询年龄大于20 并且性别是男的
{
"query": {
"bool": {
"filter": {
"range": {
"age": {
"gt": 20
}
}
},
"must": {
"match": {
"sex": "男"
}
}
}
}
}
2.12高亮显示
POST /king/_search //这里会分词搜索
{
"query": {
"match": {
"name": "张三"
}
},
"highlight": {
"fields": {
"name": {}
}
}
}
2.13聚合
这儿我只讲一部分,具体的可以看官网的介绍,具体的地址:https://www.elastic.co/guide/en/elasticsearch/reference/7.x/search-aggregations.html
avg :平均值
max:最大值
min:最小值
sum:求和
例如:查询平均年龄 (如果不指定size等于0,则还会返回10条数据)
POST /bank/_search
{
"aggs": {
"taibai": { //自定义名字
"avg": { //什么类型
"field": "age" //那个字段
}
}
},
"size": 0
}
使用脚本
POST /bank/_search
{
"aggs": {
"taibai": {
"avg": {
"script": {
"source": "doc.age.value"
}
}
}
},
"size": 0
}
cardinality : 去重统计
例如:
POST /bank/_search
{
"aggs": {
"taibai": {
"cardinality": {
"field": "age"
}
}
},
"size": 0
}
extended_stats扩展统计聚合
POST /bank/_search
{
"aggs": {
"taibai": {
"extended_stats": {
"field": "age"
}
}
},
"size": 0
}
value_count值计数统计
可以理解为统计个数
terms词聚合
基于某个field,该 field 内的每一个【唯一词元】为一个桶,并计算每个桶内文档个数。默认返回顺序是按照文档个数多少排序。
POST /bank/_search
{
"aggs": {
"taibai": {
"terms": {
"field": "age"
}
}
},
"size": 0
}
top_hits最高匹配权值聚合
获取到每组前n条数据,相当于sql 中Top(group by 后取出前n条)。它跟踪聚合中相关性最高的文档
POST /bank/_search
{
"aggs": {
"taibai": {
"terms": {
"field": "age"
},
"aggs": {
"count": {
"top_hits": {
"size": 3
}
}
}
}
},
"size": 0
}
range范围
POST bank/_search
{
"aggs": {
"group_by_age": {
"range": {
"field": "age",
"ranges": [
{
"from": 20,
"to": 30
},
{
"from": 30,
"to": 40
},
{
"from": 40,
"to": 50
}
]
}
}
},
"size": 0
}
2.14查询响应
如果使用浏览器工具去查询,返回的json没有格式化,可在后面加参数pretty,返回格式化后的数据
http://192.168.204.209:9200/taibai/_doc/_fiK3W0BdTjVHQ-c0HvY?pretty
2.15指定响应的字段
GET /king/_doc/9_iK3W0BdTjVHQ-czHuE?_source=id,name //只返回id和name字段
2.16去掉元数据
GET /king/_source/9_iK3W0BdTjVHQ-czHuE
//还可以去掉元数据并且返回指定字段
GET /king/_source/9_iK3W0BdTjVHQ-czHuE?_source=id,name
2.17判断文档是否存在
HEAD /king/_doc/9_iK3W0BdTjVHQ-czHuE
2.18批量操作
语法实例
POST _bulk
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
2.19批量查询
如果,某一条数据不存在,不影响整体响应,需要通过found的值进行判断是否查询到数据。
POST /king/_mget
{
"ids" : [ "8fiK3W0BdTjVHQ-cxntK", "9fiK3W0BdTjVHQ-cy3sI" ]
}
2.20批量插入
POST _bulk
{ "create" : { "_index" : "king", "_id" : "3" } }
{"id":2002,"name":"name1","age": 20,"sex": "男"}
{ "create" : { "_index" : "taibai", "_id" : "4" } }
{"id":2003,"name":"name1","age": 20,"sex": "男"}
2.21批量删除
POST _bulk
{ "delete" : { "_index" : "king", "_id" : "8PiK3W0BdTjVHQ-cxHs1" } }
{ "delete" : { "_index" : "king", "_id" : "6vh43W0BdTjVHQ-cHXv8" } }
2.22批量修改
POST _bulk
{ "update" : {"_id" : "4", "_index" : "king"} }
{ "doc" : {"name" : "king"} }
{ "update" : {"_id" : "3", "_index" : "king"} }
{ "doc" : {"name" : "king"} }
2.23分页查询
GET /king/_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
]
}
2.24映射
前面我们创建的索引以及插入数据,都是由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 /king/_mapping
查看指定字段的映射信息
GET /king/_mapping/field/name
2.25结构化查询
term查询
term 主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed 的字符串(未经分析的文本数据类型):
POST /king/_search
{
"query" : {
"term" : {
"age" : 20
}
}
}
terms查询
terms 跟 term 有点类似,但 terms 允许指定多个匹配条件。 如果某个字段指定了多个值,那么文档需要一起去做匹配:
POST /taibai/_search
{
"query" : {
"terms" : {
"age" : [20,27]
}
}
}
range查询
range 过滤允许我们按照指定范围查找一批数据:
gt :: 大于
gte :: 大于等于
lt :: 小于
lte :: 小于等于
POST /king/_search
{
"query": {
"range": {
"age": {
"gte": 20,
"lte": 22
}
}
}
exists查询
exists 查询可以用于查找文档中是否包含指定字段或没有某个字段,类似于SQL语句中的 IS_NULL 条件 包含这个字段就返回这条数据
POST /taibai/_search
{
"query": {
"exists": {
"field": "name"
}
}
}
match查询
match 查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它。
如果你使用 match 查询一个全文本字段,它会在真正查询之前用分析器先分析 match 一下查询字符;如果用 match 下指定了一个确切值,在遇到数字,日期,布尔值或者 not_analyzed 的字符串时,它将为你搜索你给定的值:
POST /taibai/_search
{
"query" : {
"match" : {
"name" : "三个小矮人"
}
}
}
//match查询会先对搜索词进行分词,分词完毕后再逐个对分词结果进行匹配,因此相比于term的精确搜索,match是分词匹配搜索
bool查询
bool 查询可以用来合并多个条件查询结果的布尔逻辑,它包含一下操作符:
must :: 多个查询条件的完全匹配,相当于 and 。
must_not :: 多个查询条件的相反匹配,相当于 not 。
should :: 至少有一个查询条件匹配, 相当于 or 。
这些参数可以分别继承一个查询条件或者一个查询条件的数组:
POST /king/_search
{
"query": {
"bool": {
"must": {
"term": {
"sex": "男"
}
},
"must_not": {
"term": {
"age": "29"
}
},
"should": [
{
"term": {
"sex": "男"
}
},
{
"term": {
"id": 1003
}
}
]
}
}
}
过滤查询
查询年龄为20岁的用户。
POST /king/_search
{
"query": {
"bool": {
"filter": {
"term": {
"age": 20
}
}
}
}
}
3.官方的练习
批量导入测试数据
该数据是使用www.json- http://generator.com/生成的,因此请忽略数据的实际值和语义,因为它们都是随机生成的。您可以从这里下载示例数据集(accounts.json)。将其提取到当前目录,然后按如下方式将其加载到集群中:
curl -H "Content-Type: application/json" -XPOST "localhost:9200/bank/_bulk?pretty&refresh" --data-binary "@accounts.json"
3.1给指定id加点年龄(age)
POST /bank/_update/1
{
"script": "ctx._source.age+=5"
}
3.2执行match_all
操作,并按帐户余额降序对结果进行排序,并返回前10个
GET /bank/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"balance": {
"order": "desc"
}
}
]
}
3.3如何从搜索中返回两个字段,即帐号和余额
GET /bank/_search
{
"query": {
"match_all": {}
},
"_source": ["account_number","balance"]
}
3.4返回帐户为20的
GET /bank/_search
{
"query": {
"match": {
"account_number": "20"
}
}
}
3.5返回地址中包含“mill”的所有帐户
GET /bank/_search
{
"query": {
"match": {
"address": "mill"
}
}
}
3.6返回地址中包含“mill”或“lane”的所有帐户
GET /bank/_search
{
"query": {
"match": {
"address": "mill lane"
}
}
}
3.7返回地址中包含“mill”和“lane”的所有帐户
GET /bank/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"address": "mill"
}
},
{
"match": {
"address": "lane"
}
}
]
}
}
}
3.8地址中既不包含“mill”也不包含“lane”的所有帐户
GET /bank/_search
{
"query": {
"bool": {
"must_not": [
{
"match": {
"address": "mill"
}
},
{
"match": {
"address": "lane"
}
}
]
}
}
}
3.9返回所有40岁但不居住在ID的人(state不等于ID)的账户
GET /bank/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"age": {
"value": 40
}
}
}
],
"must_not": [
{
"match": {
"state": "ID"
}
}
]
}
}
}
3.10使用bool查询返回余额在20000到30000之间的所有帐户,包括余额。换句话说,我们希望找到余额大于或等于20000,小于或等于30000的账户
GET /bank/_search
{
"query": {
"bool": {
"must": [
{
"range": {
"balance": {
"gte": 20000,
"lte": 30000
}
}
}
]
}
}
}
3.11按状态(state)对所有帐户进行分组,然后返回按count降序排列的前10个
GET /bank/_search
{
"aggs": {
"status_group": {
"terms": {
"field": "state.keyword"
}
}
},
"size": 0
}
3.12按状态计算平均帐户余额(同样只针对按count降序排列的前10个状态)
GET /bank/_search
{
"aggs": {
"status_group": {
"terms": {
"field": "state.keyword"
},
"aggs": {
"balance_avg": {
"avg": {
"field": "balance"
}
}
}
}
},
"size": 0
}
3.13基于之前(12)的聚合,我们现在按降序对平均余额排序
GET /bank/_search
{
"aggs": {
"status_group": {
"terms": {
"field": "state.keyword",
"order": {
"balance_avg": "asc"
}
},
"aggs": {
"balance_avg": {
"avg": {
"field": "balance"
}
}
}
}
},
"size": 0
}
3.14按照年龄等级(20-29岁,30-39岁,40-49岁)分组,然后按性别分组,最后得到每个年龄等级,每个性别的平均账户余额
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
}
4.中文分词
4.1Analyzer 的组成
- Character Filters (针对原始文本处理,例如,可以使用字符过滤器将印度阿拉伯数字( )转换为其等效的阿拉伯语-拉丁语(0123456789))
- Tokenizer(按照规则切分为单词),将把文本 “Quick brown fox!” 转换成 terms [Quick, brown, fox!],tokenizer 还记录文本单词位置以及偏移量。
- Token Filter(将切分的的单词进行加工、小写、刪除 stopwords,增加同义词)
4.2elasticsearch内置分词器
Standard | 默认分词器 按词分类 小写处理 |
---|---|
Simple | 按照非字母切分,非字母则会被去除 小写处理 |
**Stop ** | 小写处理 停用词过滤(the,a, is) |
**Whitespace ** | 按空格切分 |
**Keyword ** | 不分词,当成一整个 term 输出 |
**Patter ** | 通过正则表达式进行分词 默认是 \W+(非字母进行分隔) |
**Language ** | 提供了 30 多种常见语言的分词器 |
4.3分词api
POST /_analyze
{
"analyzer":"standard",
"text":"tai bai"
}
POST /_analyze
{
"analyzer":"standard",
"text":"决战到天亮"
}
英文分词 一般以空格分隔,中文分词的难点在于,在汉语中没有明显的词汇分界点,如果分隔不正确就会造成歧义。
常用中文分词器,IK、jieba、THULAC等,推荐使用IK分词器。
4.4ik分词器安装
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": "决战到天亮"
}
4.5拼音分词器
1.下载对应版本的zip包https://github.com/medcl/elasticsearch-analysis-pinyin/releases
2.可在Windows解压好,在plugins下创建pinyin文件夹
3.将解压内容放置在pinyin文件夹,重启
4.6自定义分词器
接受参数
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"
}
}
}
5.全文搜索
5.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":"听音乐、看电影、羽毛球"}
5.2单词搜索
POST /test/_search
{
"query": {
"match": {
"hobby": "音乐"
}
},
"highlight": {
"fields": {
"hobby": {}
}
}
}
5.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": {}
}
}
}
5.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": {}
}
}
}
5.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": {}
}
}
}
6.写在最后
本篇博客主要简单介绍elasticsearch的分词和简单的API。