0%

基本语法

bulk操作和以往的普通请求格式有区别。不要格式化json,不然就不在同一行了,这个需要注意。

1
2
3
4
5
{ action: { metadata }}\\n
{ request body }\\n
{ action: { metadata }}\\n
{ request body }\\n
...
  • { action: { metadata }}代表批量操作的类型,可以是新增、删除或修改
  • \\n是每行结尾必须填写的一个规范,每一行包括最后一行都要写,用于es的解析
  • { request body }是请求body,增加和修改操作需要,删除操作则不需要

批量操作的类型

action 必须是以下选项之一:

  • create:如果文档不存在,那么就创建它。存在会报错。发生异常报错不会影响其他操作。
  • index:创建一个新文档或者替换一个现有的文档。
  • update:部分更新一个文档。
  • delete:删除一个文档。

metadata 中需要指定要操作的文档的_index 、 _type 和 _id_index 、 _type也可以在url中指定

实操

create

  • create新增文档数据,在metadata中指定index以及type

    1
    2
    3
    4
    5
    6
    7
    8
    POST    /_bulk
    {"create": {"_index": "shop2", "_type": "_doc", "_id": "2001"}}
    {"id": "2001", "nickname": "name2001"}
    {"create": {"_index": "shop2", "_type": "_doc", "_id": "2002"}}
    {"id": "2002", "nickname": "name2002"}
    {"create": {"_index": "shop2", "_type": "_doc", "_id": "2003"}}
    {"id": "2003", "nickname": "name2003"}
    1234567
  • create创建已有id文档,在url中指定index和type

    1
    2
    3
    4
    5
    6
    7
    8
    POST    /shop/_doc/_bulk
    {"create": {"_id": "2003"}}
    {"id": "2003", "nickname": "name2003"}
    {"create": {"_id": "2004"}}
    {"id": "2004", "nickname": "name2004"}
    {"create": {"_id": "2005"}}
    {"id": "2005", "nickname": "name2005"}
    1234567
  • index创建,已有文档id会被覆盖,不存在的id则新增

    1
    2
    3
    4
    5
    6
    7
    8
    9
    POST    /shop/_doc/_bulk
    {"index": {"_id": "2004"}}
    {"id": "2004", "nickname": "index2004"}
    {"index": {"_id": "2007"}}
    {"id": "2007", "nickname": "name2007"}
    {"index": {"_id": "2008"}}
    {"id": "2008", "nickname": "name2008"}

    12345678

update

  • update跟新部分文档数据

    1
    2
    3
    4
    5
    POST    /shop/_doc/_bulk
    {"update": {"_id": "2004"}}
    {"doc":{ "id": "3004"}}
    {"update": {"_id": "2007"}}
    {"doc":{ "nickname": "nameupdate"}}

delete

  • delete批量删除

    1
    2
    3
    POST    /shop/_doc/_bulk
    {"delete": {"_id": "2004"}}
    {"delete": {"_id": "2007"}}

复合操作

  • 综合批量各种操作

    1
    2
    3
    4
    5
    6
    7
    POST    /shop/_doc/_bulk
    {"create": {"_id": "8001"}}
    {"id": "8001", "nickname": "name8001"}
    {"update": {"_id": "2001"}}
    {"doc":{ "id": "20010"}}
    {"delete": {"_id": "2003"}}
    {"delete": {"_id": "2005"}}

参考资源

官文:https://www.elastic.co/guide/cn/elasticsearch/guide/current/bulk.html

分页查询

1
2
3
4
5
6
7
8
POST /shop/_doc/_search
{
"query": {
"match_all": {}
},
"from": 0,
"size": 10
}

深度分页

https://raw.githubusercontent.com/littlefxc/littlefxc.github.io/images/images/es-13_1.png

深度分页其实就是搜索的深浅度,比如第1页,第2页,第10页,第20页,是比较浅的;第10000页,第20000页就是很深了。

使用如下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"query": {
"match_all": {}
},
"from": 9990,
"size": 10
}

{
"query": {
"match_all": {}
},
"from": 9999,
"size": 10
}

我们在获取第9999条到10009条数据的时候,其实每个分片都会拿到10009条数据,然后集合在一起,总共是10009*3=30027条数据,针对30027数据再次做排序处理,最终会获取最后10条数据。

如此一来,搜索得太深,就会造成性能问题,会耗费内存和占用cpu。而且es为了性能,他不支持超过一万条数据以上的分页查询。那么如何解决深度分页带来的性能呢?其实我们应该避免深度分页操作(限制分页页数),比如最多只能提供100页的展示,从第101页开始就没了,毕竟用户也不会搜的那么深,我们平时搜索淘宝或者百度,一般也就看个10来页就顶多了。

譬如淘宝搜索限制分页最多100页,如下:

https://raw.githubusercontent.com/littlefxc/littlefxc.github.io/images/images/es-13_2.jpg

通过设置index.max_result_window来突破10000数据

1
2
3
4
5
6
7
# 查询shop索引的设置
GET /shop/_settings
# 修改 shop 索引的最大返回结果
PUT /shop/_settings
{
"index.max_result_window": "20000"
}

scroll 滚动搜索

一次性查询1万+数据,往往会造成性能影响,因为数据量太多了。这个时候可以使用滚动搜索,也就是 scroll。滚动搜索可以先查询出一些数据,然后再紧接着依次往下查询。在第一次查询的时候会有一个滚动id,相当于一个锚标记,随后再次滚动搜索会需要上一次搜索的锚标记,根据这个进行下一次的搜索请求。每次搜索都是基于一个历史的数据快照,查询数据的期间,如果有数据变更,那么和搜索是没有关系的,搜索的内容还是快照中的数据。

  • scroll=1m,相当于是一个session会话时间,搜索保持的上下文时间为1分钟。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /shop/_search?scroll=1m
{
"query": {
"match_all": {
}
},
"sort" : ["_doc"],
"size": 5
}

POST /_search/scroll
{
"scroll": "1m",
"scroll_id" : "your last scroll_id"
}

mget 批量查询

26、ES中使用mget批量查询api(学习笔记,来自课程资料 + 自己整理)_涂作权的博客-CSDN博客_es mget

1 准备数据

  • 建立索引 shop(名字随意)

    1
    2
    3
    POST /shop/_mapping
    { "properties": { "id": { "type": "long" }, "age": { "type": "integer" }, "username": { "type": "keyword" }, "nickname": { "type": "text", "analyzer": "ik_max_word" }, "money": { "type": "float" }, "desc": { "type": "text", "analyzer": "ik_max_word" }, "sex": { "type": "byte" }, "birthday": { "type": "date" }, "face": { "type": "text", "index": false } }
    }
  • 录入数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    POST /shop/_doc/1001
    {
    "id": 1001,
    "age": 18,
    "username": "imoocAmazing",
    "nickname": "慕课网",
    "money": 88.8,
    "desc": "我在慕课网学习java和前端,学习到了很多知识",
    "sex": 0,
    "birthday": "1992-12-24",
    "face": "https://www.imooc.com/static/img/index/logo.png"
    }

    POST /shop/_doc/1002
    {
    "id": 1002,
    "age": 19,
    "username": "justbuy",
    "nickname": "周杰棍",
    "money": 77.8,
    "desc": "今天上下班都很堵,车流量很大",
    "sex": 1,
    "birthday": "1993-01-24",
    "face": "https://www.imooc.com/static/img/index/logo.png"
    }

    POST /shop/_doc/1003
    {
    "id": 1003,
    "age": 20,
    "username": "bigFace",
    "nickname": "飞翔的巨鹰",
    "money": 66.8,
    "desc": "慕课网团队和导游坐飞机去海外旅游,去了新马泰和欧洲",
    "sex": 1,
    "birthday": "1996-01-14",
    "face": "https://www.imooc.com/static/img/index/logo.png"
    }

    POST /shop/_doc/1004
    {
    "id": 1004,
    "age": 22,
    "username": "flyfish",
    "nickname": "水中鱼",
    "money": 55.8,
    "desc": "昨天在学校的池塘里,看到有很多鱼在游泳,然后就去慕课网上课了",
    "sex": 0,
    "birthday": "1988-02-14",
    "face": "https://www.imooc.com/static/img/index/logo.png"
    }

    POST /shop/_doc/1005
    {
    "id": 1005,
    "age": 25,
    "username": "gotoplay",
    "nickname": "ps游戏机",
    "money": 155.8,
    "desc": "今年生日,女友送了我一台play station游戏机,非常好玩,非常不错",
    "sex": 1,
    "birthday": "1989-03-14",
    "face": "https://www.imooc.com/static/img/index/logo.png"
    }

    POST /shop/_doc/1006
    {
    "id": 1006,
    "age": 19,
    "username": "missimooc",
    "nickname": "我叫小慕",
    "money": 156.8,
    "desc": "我叫凌云慕,今年20岁,是一名律师,我在琦䯲星球做演讲",
    "sex": 1,
    "birthday": "1993-04-14",
    "face": "https://www.imooc.com/static/img/index/logo.png"
    }

    POST /shop/_doc/1007
    {
    "id": 1007,
    "age": 19,
    "username": "msgame",
    "nickname": "gamexbox",
    "money": 1056.8,
    "desc": "明天去进货,最近微软处理很多游戏机,还要买xbox游戏卡带",
    "sex": 1,
    "birthday": "1985-05-14",
    "face": "https://www.imooc.com/static/img/index/logo.png"
    }

    POST /shop/_doc/1008
    {
    "id": 1008,
    "age": 19,
    "username": "muke",
    "nickname": "慕学习",
    "money": 1056.8,
    "desc": "大学毕业后,可以到imooc.com进修",
    "sex": 1,
    "birthday": "1995-06-14",
    "face": "https://www.imooc.com/static/img/index/logo.png"
    }

    POST /shop/_doc/1009
    {
    "id": 1009,
    "age": 22,
    "username": "shaonian",
    "nickname": "骚年轮",
    "money": 96.8,
    "desc": "骚年在大学毕业后,考研究生去了",
    "sex": 1,
    "birthday": "1998-07-14",
    "face": "https://www.imooc.com/static/img/index/logo.png"
    }

    POST /shop/_doc/1010
    {
    "id": 1010,
    "age": 30,
    "username": "tata",
    "nickname": "隔壁老王",
    "money": 100.8,
    "desc": "隔壁老外去国外出差,带给我很多好吃的",
    "sex": 1,
    "birthday": "1988-07-14",
    "face": "https://www.imooc.com/static/img/index/logo.png"
    }

    POST /shop/_doc/1011
    {
    "id": 1011,
    "age": 31,
    "username": "sprder",
    "nickname": "皮特帕克",
    "money": 180.8,
    "desc": "它是一个超级英雄",
    "sex": 1,
    "birthday": "1989-08-14",
    "face": "https://www.imooc.com/static/img/index/logo.png"
    }

    POST /shop/_doc/1012
    {
    "id": 1012,
    "age": 31,
    "username": "super hero",
    "nickname": "super hero",
    "money": 188.8,
    "desc": "BatMan, GreenArrow, SpiderMan, IronMan... are all Super Hero",
    "sex": 1,
    "birthday": "1980-08-14",
    "face": "https://www.imooc.com/static/img/index/logo.png"
    }

2 使用 QueryString 查询

查询[字段]包含[内容]的文档

1
2
GET /shop/_doc/_search?q=desc:慕课网
GET /shop/_doc/_search?q=nickname:慕&q=age:25

3 DSL

3.1 match - 查询

全文检索

1
2
3
4
5
6
7
8
POST /shop/_search
{
"query": {
"match": {
"desc": "慕课网"
}
}
}

3.2 exists - 判断某个字段是否存在

exists可以理解为SQL中的exists函数,就是判断是否存在该字段。

1
2
3
4
5
6
7
8
POST /shop/_search
{
"query": {
"exists": {
"field": "desc"
}
}
}

3.3 match_all - 查询所有与分页

可以查询集群所有索引库的信息,包括一些隐藏索性库的信息。

3.3.1 在索引中查询所有的文档

1
GET /shop/_doc/_search

或者指定返回属性

1
2
3
4
5
6
7
POST /shop/_doc/_search
{
"query": {
"match_all": {}
},
"_source": ["id", "nickname", "age"]
}
  • Head 可视化操作

    https://raw.githubusercontent.com/littlefxc/littlefxc.github.io/images/images/match_all_12_1.jpg

3.3.2 分页查询

默认查询是只有10条记录,可以通过分页来展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
POST /shop/_doc/_search
{
"query": {
"match_all": {}
},
"from": 0,
"size": 10
}

POST /shop/_doc/_search
{
"query": {
"match_all": {}
},
"_source": [
"id",
"nickname",
"age"
],
"from": 5,
"size": 5
}
  • Head 可视化操作

    https://raw.githubusercontent.com/littlefxc/littlefxc.github.io/images/images/match_all_12_2.jpg

3.4 term - 精确查询

term主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed 的字符串(未经分析的文本数据类型)

3.4.1 term精确搜索与match分词搜索

搜索的时候会把用户搜索内容,比如“慕课网强大”作为一整个关键词去搜索,而不会对其进行分词后再搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST /shop/_doc/_search
{
"query": {
"term": {
"desc": "慕课网"
}
}
}
对比
POST /shop/_doc/_search
{
"query": {
"match": {
"desc": "慕课网"
}
}
}
  • 注:match会对慕课网慕课网

    先进行分词(其实就是全文检索),在查询,而term则不会,直接把

    作为一个整的词汇去搜索。

  • head 可视化操作对比:

    https://climg.mukewang.com/5df73ae408b52e4b14850283.jpg

    https://climg.mukewang.com/5df73af9088d880314890314.jpg

3.4.2 terms 多个词语匹配检索

相当于是tag标签查询,比如慕课网的一些课程会打上前端/后端/大数据/就业课这样的标签,可以完全匹配做类似标签的查询

1
2
3
4
5
6
7
8
POST /shop/_doc/_search
{
"query": {
"terms": {
"desc": ["慕课网", "学习", "骚年"]
}
}
}

3.5 match_phrase

match:分词后只要有匹配就返回,match_phrase:分词结果必须在text字段分词中都包含,而且顺序必须相同,而且必须都是连续的。(搜索比较严格)

slop:允许词语间跳过的数量

1
2
3
4
5
6
7
8
9
10
11
POST /shop/_doc/_search
{
"query": {
"match_phrase": {
"desc": {
"query": "大学 毕业 研究生",
"slop": 2
}
}
}
}

3.6 match(operator)/ids

3.6.1 match 扩展

  • operator

    • or:搜索内容分词后,只要存在一个词语匹配就展示结果
    • and:搜索内容分词后,都要满足词语匹配
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    POST     /shop/_doc/_search
    {
    "query": {
    "match": {
    "desc": "慕课网"
    }
    }
    }
    # 等同于
    {
    "query": {
    "match": {
    "desc": {
    "query": "xbox游戏机",
    "operator": "or"
    }
    }
    }
    }
    # 相当于 select * from shop where desc='xbox' or|and desc='游戏机'
  • minimum_should_match: 最低匹配精度,至少有[分词后的词语个数]x百分百,得出一个数据值取整。举个例子:当前属性设置为70,若一个用户查询检索内容分词后有10个词语,那么匹配度按照 10x70%=7,则desc中至少需要有7个词语匹配,就展示;若分词后有8个,则 8x70%=5.6,则desc中至少需要有5个词语匹配,就展示。

    minimum_should_match 也能设置具体的数字,表示个数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    POST /shop/_doc/_search
    {
    "query": {
    "match": {
    "desc": {
    "query": "女友生日送我好玩的xbox游戏机",
    "minimum_should_match": "60%"
    }
    }
    }
    }

3.6.2 根据文档主键ids搜索

1
GET /shop/_doc/1001

查询多个

1
2
3
4
5
6
7
8
9
POST /shop/_doc/_search
{
"query": {
"ids": {
"type": "_doc",
"values": ["1001", "1010", "1008"]
}
}
}

3.7 multi_match/boost

3.7.1 multi_match - 多字段查询

满足使用match在多个字段中进行查询的需求

1
2
3
4
5
6
7
8
9
POST /shop/_doc/_search
{
"query": {
"multi_match": {
"query": "皮特帕克慕课网",
"fields": ["desc", "nickname"]
}
}
}

3.7.2 boost - 权重

权重,为某个字段设置权重,权重越高,文档相关性得分就越高。通畅来说搜索商品名称要比商品简介的权重更高。

1
2
3
4
5
6
7
8
9
10
POST /shop/_doc/_search
{
"query": {
"multi_match": {
"query": "皮特帕克慕课网",
"fields": ["desc", "nickname^10"]

}
}
}

nickname^10 代表搜索提升10倍相关性,也就是说用户搜索的时候其实以这个nickname为主,desc为辅,nickname的匹配相关度当然要提高权重比例了。

3.8 bool - 布尔查询

可以组合多重查询

  • must:查询必须匹配搜索条件,譬如 and

  • should:查询匹配满足1个以上条件,譬如 or

  • must_not:不匹配搜索条件,一个都不要满足

  • 实操1:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    POST /shop/_doc/_search
    {
    "query": {
    "bool": {
    "must": [
    {
    "multi_match": {
    "query": "慕课网",
    "fields": ["desc", "nickname"]
    }
    },
    {
    "term": {
    "sex": 1
    }
    },
    {
    "term": {
    "birthday": "1996-01-14"
    }
    }
    ]
    }
    }
    }

    POST /shop/_doc/_search
    {
    "query": {
    "bool": {
    "should(must_not)": [
    {
    "multi_match": {
    "query": "学习",
    "fields": ["desc", "nickname"]
    }
    },
    {
    "match": {
    "desc": "游戏"
    }
    },
    {
    "term": {
    "sex": 0
    }
    }
    ]
    }
    }
    }
  • 实操2:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    POST /shop/_doc/_search
    {
    "query": {
    "bool": {
    "must": [
    {
    "match": {
    "desc": "慕"
    }
    },
    {
    "match": {
    "nickname": "慕"
    }
    }
    ],
    "should": [
    {
    "match": {
    "sex": "0"
    }
    }
    ],
    "must_not": [
    {
    "term": {
    "birthday": "1992-12-24"
    }
    }
    ]
    }
    }
    }
  • Head 可视化组合查询

    https://raw.githubusercontent.com/littlefxc/littlefxc.github.io/images/images/es-12_3.jpg

  • 为指定词语加权

    特殊场景下,某些词语可以单独加权,这样可以排得更加靠前。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    POST /shop/_doc/_search
    {
    "query": {
    "bool": {
    "should": [
    {
    "match": {
    "desc": {
    "query": "律师",
    "boost": 18
    }
    }
    },
    {
    "match": {
    "desc": {
    "query": "进修",
    "boost": 2
    }
    }
    }
    ]
    }
    }
    }

3.9 post_filter - 过滤器

对搜索出来的结果进行数据过滤。不会到es库里去搜,不会去计算文档的相关度分数,所以过滤的性能会比较高,过滤器可以和全文搜索结合在一起使用。post_filter元素是一个顶层元素,只会对搜索结果进行过滤。不会计算数据的匹配度相关性分数,不会根据分数去排序,query则相反,会计算分数,也会按照分数去排序。

使用场景:

  • query:根据用户搜索条件检索匹配记录
  • post_filter:用于查询后,对结果数据的筛选

实操:查询账户金额大于80元,小于160元的用户。并且生日在1998-07-14的用户

  • gte:大于等于
  • lte:小于等于
  • gt:大于
  • lt:小于(除此以外还能做其他的match等操作也行)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST /shop/_doc/_search

{
"query": {
"match": {
"desc": "慕课网游戏"
}
},
"post_filter": {
"range": {
"money": {
"gt": 60,
"lt": 1000
}
}
}
}

3.10 sort - 排序

es的排序同sql,可以desc也可以asc。也支持组合排序。

  • 实操:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    POST /shop/_doc/_search
    {
    "query": {
    "match": {
    "desc": "慕课网游戏"
    }
    },
    "post_filter": {
    "range": {
    "money": {
    "gt": 55.8,
    "lte": 155.8
    }
    }
    },
    "sort": [
    {
    "age": "desc"
    },
    {
    "money": "desc"
    }
    ]
    }
  • 对文本排序

    由于文本会被分词,所以往往要去做排序会报错,通常我们可以为这个字段增加额外的一个附属属性,类型为keyword,用于做排序。

    1. 创建新的索引

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      POST /shop2/_mapping
      {
      "properties": {
      "id": {
      "type": "long"
      },
      "nickname": {
      "type": "text",
      "analyzer": "ik_max_word",
      "fields": {
      "keyword": {
      "type": "keyword"
      }
      }
      }
      }
      }
    2. 插入数据

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      POST /shop2/_doc
      {
      "id": 1001,
      "nickname": "美丽的风景"
      }

      POST /shop2/_doc
      {
      "id": 1002,
      "nickname": "漂亮的小哥哥"
      }

      POST /shop2/_doc
      {
      "id": 1003,
      "nickname": "飞翔的巨鹰"
      }

      POST /shop2/_doc
      {
      "id": 1004,
      "nickname": "完美的天空"
      }

      POST /shop2/_doc
      {
      "id": 1005,
      "nickname": "广阔的海域"
      }
    3. 排序

      1
      2
      3
      4
      5
      6
      7
      8
      POST /shop2/_doc/_search
      {
      "sort": [
      {
      "nickname.keyword": "desc"
      }
      ]
      }

3.11 highlight - 高亮显示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /shop/_doc/_search
{
"query": {
"match": {
"desc": "慕课网"
}
},
"highlight": {
"pre_tags": ["<span>"],
"post_tags": ["</span>"],
"fields": {
"desc": {}
}
}
}

3.12 prefix - 前缀

根据前缀去查询

1
2
3
4
5
6
7
8
POST /shop/_doc/_search
{
"query": {
"prefix": {
"desc": "imo"
}
}
}

3.13 fuzzy - 模糊搜索

模糊搜索,并不是指的sql的模糊搜索,而是用户在进行搜索的时候的打字错误现象,搜索引擎会自动纠正,然后尝试匹配索引库中的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
POST /shop/_doc/_search
{
"query": {
"fuzzy": {
"desc": "imoov.coom"
}
}
}
# 或多字段搜索
POST /shop/_doc/_search
{
"query": {
"multi_match": {
"fields": [ "desc", "nickname"],
"query": "imcoc supor",
"fuzziness": "AUTO"
}
}
}

POST /shop/_doc/_search
{
"query": {
"multi_match": {
"fields": [ "desc", "nickname"],
"query": "演说",
"fuzziness": "1"
}
}
}

3.14 wildcard - 占位符查询

占位符查询。

什么是分词?

把文本转换为一个个的单词,分词称之为analysis。es默认只对英文语句做分词,中文不支持,每个中文字都会被拆分为独立的个体。

  • 英文分词:I study in imooc.com
  • 中文分词:我在慕课网学习
1
2
3
4
5
6
7
8
9
10
11
POST /_analyze
{
"analyzer": "standard",
"text": "text文本"
}
POST /my_doc/_analyze
{
"analyzer": "standard",
"field": "name",
"text": "text文本"
}

es内置分词器

  • standard:默认分词,单词会被拆分,大小会转换为小写。

  • simple:按照非字母分词。大写转为小写。

  • whitespace:按照空格分词。忽略大小写。

  • stop:去除无意义单词,比如the/a/an/is

  • keyword:不做分词。把整个文本作为一个单独的关键词。

    1
    2
    3
    4
    {
    "analyzer": "standard",
    "text": "My name is Peter Parker,I am a Super Hero. I don't like the Criminals."
    }

观察操作

  • 插入新数据

    1
    2
    3
    4
    5
    6
    7
    8
    POST /my_doc/_doc
    {
    "id": 1010,
    "name": "imooc-1010",
    "desc": "imoocimooc!",
    "create_date": "2019-12-24"
    }
    # 此时 _version 为 1
  • 修改数据

    1
    2
    3
    4
    5
    6
    7
    8
    POST    /my_doc/_doc/{_id}/_update
    {
    "doc": {
    "name": "慕课"
    }
    }
    # 此时 _version 为 2
    1234567
  • 模拟两个客户端操作同一个文档数据,_version都携带为一样的数值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 操作1
    POST /my_doc/_doc/{_id}/_update?if_seq_no={数值}&if_primary_term={数值}
    {
    "doc": {
    "name": "慕课1"
    }
    }

    # 操作2
    POST /my_doc/_doc/{_id}/_update?if_seq_no={数值}&if_primary_term={数值}
    {
    "doc": {
    "name": "慕课2"
    }
    }

    版本元数据

1 Consul 单机集群搭建

本文是在生产环境中Consul服务端节点不稳定后,导致注册到Consul集群上的部分服务不可用,从而造成开放能力平台无法使用的背景下产生的。

目的是探讨一个高可用Consul集群方案。

1.1 consul 架构

Server负责组成 cluster 的复杂工作(选举、状态维护、转发请求到 lead),以及 consul 提供的服务(响应 RCP 请求)。考虑到容错和收敛,一般部署 3 ~ 5 个比较合适,而client数量不做限制,架构如下:

consul 架构

1.2 Consul 节点规划

节点名称 节点类型 HTTP端口 DNS端口 serf_lan端口 serf_wan端口
consul-server-1 server 8501 8601 8001 8002
consul-server-2 server 8502 8602 8101 8102
consul-server-3 server 8503 8603 8201 8202
consul-client-1 client 8504 8604 8301 8302
consul-client-2 client 8505 8605 8401 8402

1.3 Consul 服务端节点配置文件模版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
"bind_addr": "127.0.0.1",
"client_addr": "127.0.0.1",
"ports": {
"http": 8501,
"dns": 8601,
"serf_lan": 8001,
"serf_wan": 8002,
"server": 8000
},
"datacenter": "dc1",
"data_dir": "/Users/fengxuechao/WorkSpace/IdeaProjects/consul/consul-server-1/data",
"log_level": "INFO",
"log_file": "/Users/fengxuechao/WorkSpace/IdeaProjects/consul/consul-server-1/log/consul.log",
"node_name": "consul-server-1",
"disable_host_node_id": true,
"server": true,
"ui": true,
"bootstrap_expect": 3,
"rejoin_after_leave": true,
"retry_join": [
"127.0.0.1:8001",
"127.0.0.1:8101",
"127.0.0.1:8201"
]
}

注意:

  • disable_host_node_id:不使用host信息生成node ID,适用于同一台服务器部署多个实例用于测试的情况。随机生成nodeID。

1.4 Consul 客户端节点配置文件模版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"bind_addr": "127.0.0.1",
"client_addr": "127.0.0.1",
"ports": {
"http": 8505,
"dns": 8605,
"serf_lan": 8401,
"serf_wan": 8402,
"server": 8400
},
"datacenter": "dc1",
"data_dir": "/Users/fengxuechao/WorkSpace/IdeaProjects/consul/consul-client-2/data",
"log_level": "INFO",
"log_file": "/Users/fengxuechao/WorkSpace/IdeaProjects/consul/consul-client-2/log/consul.log",
"node_name": "consul-client-2",
"disable_host_node_id": true,
"server": false,
"ui": true,
"rejoin_after_leave": true,
"retry_join": [
"127.0.0.1:8001",
"127.0.0.1:8101",
"127.0.0.1:8201"
]
}

1.5 搭建集群

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 创建 Consul 服务端节点目录
mkdir consul-server-{1,2,3}
# 创建 Consul 服务端节点可执行文件目录
mkdir consul-server-{1,2,3}/bin
# 创建 Consul 服务端节点配置文件目录
mkdir consul-server-{1,2,3}/config
# 创建 Consul 服务端节点数据文件目录
mkdir consul-server-{1,2,3}/data
# 创建 Consul 服务端节点日志文件目录
mkdir consul-server-{1,2,3}/log

# consul 客户端节点目录结构与服务端节点目录结构保持一致
...

# Consul 服务端节点搭建
nohup consul-server-1/bin/consul agent -config-dir=consul-server-1/config &
nohup consul-server-2/bin/consul agent -config-dir=consul-server-2/config &
nohup consul-server-3/bin/consul agent -config-dir=consul-server-3/config &
# Consul 客户端节点搭建
nohup consul-client-1/bin/consul agent -config-dir=consul-client-1/config &
nohup consul-client-2/bin/consul agent -config-dir=consul-client-2/config &

2 Consul 的一些命令

2.1 查看 consul 集群列表

验证 Consul 集群是否搭建成功

1
consul-server-1/bin/consul operator raft list-peers -http-addr=127.0.0.1:8501

2.2 查看 Consul 节点列表

查看 Consul 的所有节点列表

1
consul-server-1/bin/consul members -http-addr=127.0.0.1:8501

2.3 移除一个 Server 节点

验证 Consul 客户端节点不会丢失

1
consul-server-1/bin/consul leave -http-addr=127.0.0.1:8501

3 验证

3.1 模拟一个 Consul 服务端宕机

  1. 移除 Consul 服务端节点前:

image-20210112101929745

  1. 移除 Consul 服务端节点。命令参考章节2.3。

    结果如下:

    image-20210112102147403

    image-20210112102223434

4 结论

说明当一个consul服务端节点宕机,并不会影响 Consul 客户端节点的可用性。

在每个数据中心,client和server是混合的。一般建议有3-5台server。这是基于有故障情况下的可用性和性能之间的权衡结果,因为越多的机器加入达成共识越慢。虽然每个节点的服务注册数量是有上限的,但是并不限制client的数量,它们可以很容易的扩展到数千或者数万台。

5 参考资源

https://blog.csdn.net/u014635374/article/details/106313858

转载自 https://blog.csdn.net/qq_36986015/article/details/106802555

1. 缓存过期机制

Redis可以通过设置一个过期时间expire来处理缓存,其中处理方式有两种:

  1. (主动)定期删除,Redis会抽查随机的key,默认1秒十次,一旦抽查的key过期了,就会给删除,配置的属性在redis.conf中,hz等于10,表示1秒抽查10次

    1
    hz 10
  2. (被动)惰性删除,key到期后不去主动检测,而是请求访问到这个key之后,会检查下是否过期,这样就不会太消耗CPU资源,缺点是一直占用着内存

2. 内存淘汰管理机制

因为计算机的内存是有限的,在部署Redis的同时,也可能部署其他的中间件如RabbitMQ、Kafka等等,为了给其他中间件预留内存空间,Redis服务启动可以设置一个最大内存maxmemory,到达阈值后,Redis会清理在内存里永久存在的没有过期时间的key,处理机制如下:

1
2
maxmemory :当内存已使用率到达,则开始清理缓存
maxmemory-policy : 清理缓存的策略

清理缓存的策略如下所示:

  • noeviction:旧缓存永不过期,新缓存设置不了,返回错误
  • allkeys-lru:清除最少用的旧缓存,然后保存新的缓存(推荐使用)
  • allkeys-random:在所有的缓存中随机删除(不推荐)
  • volatile-lru:在那些设置了expire过期时间的缓存中,清除最少用的旧缓存,然后保存新的缓存
  • volatile-random:在那些设置了expire过期时间的缓存中,随机删除缓存
  • volatile-ttl:在那些设置了expire过期时间的缓存中,删除即将过期的

注意:

LRU 和 LFU 的含义:

    # LRU means Least Recently Used
    # LFU means Least Frequently Used

redis.conf 配置

1
2
3
4
5
6
7
8
# 开启集群模式
cluster-enabled yes
# 每一个节点需要有一个配置文件,需要6份。每个节点处于集群的角色都需要告知其他所有节点,彼此知道,这个文件用于存储集群模式下的集群状态等信息,这个文件是由redis自己维护,我们不用管。如果你要重新创建集群,那么把这个文件删了就行
cluster-config-file nodes-201.conf
# 超时时间,超时则认为master宕机,随后主备切换
cluster-node-timeout 5000
# 开启AOF
appendonly yes

启动6个redis实例

  1. 启动6台
  2. 如果启动过程出错,把rdb等文件删除清空

创建集群

1
2
3
4
5
6
7
#####
# 注意1:如果你使用的是redis3.x版本,需要使用redis-trib.rb来构建集群,最新版使用C语言来构建了,这个要注意
# 注意2:以下为新版的redis构建方式
#####

# 创建集群,主节点和从节点比例为1,1-3为主,4-6为从,1和4,2和5,3和6分别对应为主从关系,这也是最经典用的最多的集群模式
redis-cli -a 密码 --cluster create ip1:port1 ip2:port2 ip3:port3 ip4:port4 ip5:port5 ip6:port6 --cluster-replicas 1

slots:槽,用于装数据,主节点有,从节点没有

检查集群信息

1
redis-cli --cluster check 192.168.25.64:6380

[TOC]

1 集群健康

集群健康 | Elasticsearch: 权威指南 | Elastic

1
GET /_cluster/health

2 索引相关

2.1 创建索引

1
2
3
4
5
6
7
8
9
PUT /index_test
{
"settings": {
"index": {
"number_of_shards": "2",
"number_of_replicas": "0"
}
}
}
  • number_of_shards : 分片数
  • number_of_replicas : 副本数

2.2 查看索引

1
GET _cat/indices?v

2.3 删除索引

1
DELETE /index_test

3 mappings 相关

3.1 创建索引的同时创建mappings

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
PUT /index_test
{
"settings": {
"index": {
"number_of_shards": "3",
"number_of_replicas": "0"
}
},
"mappings": {
"properties": {
"realname": {
"type": "text",
"index": true
},
"username": {
"type": "keyword",
"index": false
},
"id": {
"type": "long"
},
"age": {
"type": "integer"
},
"nickname": {
"type": "keyword"
},
"money1": {
"type": "float"
},
"money2": {
"type": "double"
},
"sex": {
"type": "byte"
},
"score": {
"type": "short"
},
"is_teenager": {
"type": "boolean"
},
"birthday": {
"type": "date"
},
"relationship": {
"type": "object"
}
}
}
}

注意:

  • number_of_shards : 分片数

  • number_of_replicas : 副本数

  • index:默认true,设置为false的话,那么这个字段就不会被索引(例如密码等敏感信息)

  • 某个属性一旦被建立,就不能修改了,但是可以新增额外属性

  • 主要数据类型:

    • text, keyword, string
    • long, integer, short, byte
    • double, float
    • boolean
    • date
    • object
    • 数组不能混,类型一致
  • text:文字类需要被分词被倒排索引的内容,比如商品名称商品详情商品介绍,使用text。

  • keyword:不会被分词,不会被倒排索引,直接匹配搜索,比如订单状态用户qq微信号手机号等,这些精确匹配,无需分词。

4 文档的基本操作

4.1 添加文档

1
2
3
4
5
6
7
8
9
POST /{索引名}/_doc/{索引ID}(是指索引在es中的id,而不是这条记录的id,比如记录的id从数据库来是1001,并不是这个。如果不写,则自动生成一个字符串。建议和数据id保持一致> )

POST /user/_doc/1
{
"id": 1,
"username": "username1",
"password": "password1",
"create_date": "2021-01-09"
}

查看索引

1
GET /user

结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
{
"user" : {
"aliases" : { },
"mappings" : {
"properties" : {
"create_date" : {
"type" : "date"
},
"id" : {
"type" : "long"
},
"password" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"username" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
},
"settings" : {
"index" : {
"creation_date" : "1610183188727",
"number_of_shards" : "1",
"number_of_replicas" : "1",
"uuid" : "55w3gLZNTVyJnmdi6hTo5g",
"version" : {
"created" : "7100099"
},
"provided_name" : "user"
}
}
}
}

注意

  • 如果索引没有手动建立mappings,那么当插入文档数据的时候,会根据文档类型自动设置属性类型。这个就是es的动态映射,帮我们在index索引库中去建立数据结构的相关配置信息。
  • “fields”: {“type”: “keyword”}对一个字段设置多种索引模式,使用text类型做全文检索,也可使用keyword类型做聚合和排序
  • “ignore_above” : 256设置字段索引和存储的长度最大值,超过则被忽略

4.2 修改文档

4.2.1 局部修改

1
2
3
4
5
6
POST /user/_doc/1/_update
{
"doc": {
"name": "update1"
}
}

4.2.2 全局修改

1
2
3
4
5
6
7
PUT /user/_doc/1
{
"id": 1,
"username": "update2",
"password": "password1",
"create_date": "2021-01-09"
}

同时每次修改后,返回参数中的属性 verison 都会更改

4.3 删除文档

1
DELETE /user/_doc/1

:文档删除不是立即删除,文档还是保存在磁盘上,索引增长越来越多,才会把那些曾经标识过删除的,进行清理,从磁盘上移出去。

4.4 查询文档

常规查询

1
2
GET /index_demo/_doc/1
GET /index_demo/_doc/_search

4.4.1 查询结果

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"_index": "my_doc",
"_type": "_doc",
"_id": "2",
"_score": 1.0,
"_version": 9,
"_source": {
"id": 1002,
"name": "imooc-2",
"desc": "imooc is fashion",
"create_date": "2019-12-25"
}
}

4.4.2 元数据

  • _index:文档数据所属那个索引,理解为数据库的某张表即可。
  • _type:文档数据属于哪个类型,新版本使用_doc
  • _id:文档数据的唯一标识,类似数据库中某张表的主键。可以自动生成或者手动指定。
  • _score:查询相关度,是否契合用户匹配,分数越高用户的搜索体验越高。
  • _version:版本号。
  • _source:文档数据,json格式。

4.4.3 定制结果集

1
2
GET /index_demo/_doc/1?_source=id,name
GET /index_demo/_doc/_search?_source=id,name

4.4.4 判断文档是否存在

1
HEAD /index_demo/_doc/1

前言

在学习 ES 的过程中,简单的介绍下倒排索引是怎么回事,对倒排索引有一个宏观的感受。

正排索引

在讲述倒排索引之前先介绍下正排索引。正排索引就是如下表形式:

文档id 文档内容
1 什么是正排索引
2 什么是倒排索引
3 正排索引和倒排索引
阅读全文 »