一、 多索引查询
GET /lib1/_search
GET /lib*/_search
GET /lib1,lib2/_search
GET /lib1,lib2/_search
GET /_all/_search
GET _search
二、 分页查询中的deep paging(深度分页)问题
GET /myindex/_search
{
"from":0,
"size":3,
"version":true,
"query":{
"match":{
"intrest":"basketball running"
}
}
}
GET /_search?from=0&size=3
deep paging : 查询的很深,比如一个索引有三个primary shard,分别存储了6000条数据,我们要得到笫100页的数据(每页10条),类似这种情况就叫deep paging
1. 如何得到笫100页的10条数据?
1.1 深度分页的错误做法
在每个shard中搜索990到999这10条数据,然后用这30条数据排序,排序之后取10条数据就是要搜索的数据,这种做法是❌的,因为3个shard中的数据的
_score分数不一祥,可能某一个shard中第一条数据的_score分数比另一个shard中笫1000条都要高,所以在每个shard中搜索990到999这10条数据然后排 序的倣法是不正确的。
1.2 深度分页的正确做法
是每个shard把0到999条数据全部搜索出来(按排序顺序),然后全部返回给coordinate node•甶coordinate按_score分数排序后,出第 100页的10条数据,然后返回绐客户端,
1.3 deep paging性能问题
- 耗费网络芾宽,因为搜索过深的话,各shard要把数据传送绐coordinate node,这个过程是有大量数据传递的,消耗网络。
- 消耗内存,各shard要把数据恃送给coordinate node,这个传递回来的数振,是被coordinate nodW存在内存中的,这样今大量消耗内存.
-
消耗cpu coordinate node要把传回来的数据逬行排序,这个排序过程很消耗cpu.
鉴于deep paging的性能间题,所以应尽量减少使用
三、query String 查询以及copy_to
get /lib1/_search?q=name:xiaochao
get /lib1/_search?q=+name:xiaochao
get /lib1/_search?q=-name:xiaochao
copy_to字段是把其它字段中的值,以空格为分隔符组成一个大字符串,然后被分析和索引,但是不存储,不能显示,只能用来做查询参数。字段类型必须为text
//
DELETE /testindex
#copy_to mapping 提高搜索效率
PUT /testindex
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 0
},
"mappings": {
"properties": {
"age" : {"type" : "long"},
"birthday" : {"type" : "date"},
"name" : {"type" : "text","copy_to": "fullContent"},#自定义copy_to字段名
"content":{"type":"text","copy_to": "fullContent"},#自定义copy_to字段名
"price":{"type": "double"},
"number":{"type": "integer"}
}
}
}
#数据1
PUT /testindex/_doc/xiaochao
{
"name":"xiaochao",
"age":22,
"birthday":"1991-02-23",
"content":"good boy",
"price":100,
"number":1
}
#数据2
PUT /testindex/_doc/xiaoyi
{
"name":"xiaoyi",
"age":22,
"birthday":"1992-02-23",
"content":"good girl",
"price":100,
"number":1
}
#数据3
PUT /testindex/_doc/xiaofei
{
"name":"xiaofei",
"age":22,
"birthday":"1997-02-23",
"content":"little girl",
"price":100,
"number":1
}
#通过copy_to字段索引,避免全字段检索
GET /testindex/_search?q=fullContent:xiaofei
四、字符型排序
ES对字符串分词了,所以对字符串类型排序不准确,会报错。解决办法:
对字段索引2次,一次索引分词,用于搜索;一次索引不分词,用于排序。
DELETE test1
//
PUT /test1
{
"mappings": {
"properties": {
"age" : {"type" : "long"},
"birthday" : {"type" : "date","index": false},
"name" : {
"type" : "text",
"fields" : {
"raw" : {
"type" : "keyword" #fields.raw.type=keyword是必须的
}
},
"fielddata":true #这个必须的
}
}
}
}
#文档1
PUT /test1/_doc/1
{
"age":10,
"birthday":"2019-09-23",
"name":"xiaochao"
}
#文档2
PUT /test1/_doc/2
{
"age":20,
"birthday":"2019-02-23",
"name":"xiaoyi"
}
#文档3
PUT /test1/_doc/3
{
"age":30,
"birthday":"2019-07-23",
"name":"xiaofei"
}
#text查询排序
GET /test1/_search
{
"query":{
"match_all": {}
},
"sort": [
{
"name.raw": { #.raw是根据整个文本排序,而不是被分的词
"order": "asc"
}
}
]
}
五、如何计算相关度分数
使用的是TF/IDF算法(Term Frequency&lnverse Document Frequency)
-
Term Frequency(词条频率) 我们查询的文本中的词条在 document本 中出现了多少次,出现次数越多,相关度越高
搜索内容:hello world
#
Hello, I love china.
Hello world,how are you!
2.lnverse Document Frequency(倒排索引频率): 我们查询的文本中的词条在 索引的所有文档中 出现了多少次,出现的次数越多,相关度越低
搜索内容:hello world
//hello在索引的 所有文档中 出现了500次,world出现了 100次
//所有
hello, what are you doing?
I like the world.
-
Field-length(字段长度归约)norm : field越长相关度越低
搜索内容:hello world
//hello 所在文本短,得分高
{'title':"hello,what's your name?',',content':{'owieurowieuolsdjflk'}}
#world所在文本长,得分低
{'title':'hi,good morning','contenf:{'lkjkljkj................world'}}
查看分数是如何计算的:
GET /myindex/_search?explain=true
GET /myindex/_doc/_explain
{
"query":{
"match":{
"intrest":"qwer"
}
}
}
#没有article10的文档
GET /myindex/_doc/article10/_explain
{
"query":{
"match":{
"intrest":"basketball running"
}
}
}
--------------------------------
# Deprecation: [types removal] Specifying a type in explain requests is deprecated.
{
"_index" : "myindex",
"_type" : "_doc",
"_id" : "article10",
"matched" : false
}
六、 Doc Values 解析 (正排索引)
DocValues其实是Lucene在构建倒排索引时,会额外建立一个有序的正排索引(基于 document => field value的映射列表)
{'birthday':'1985-11-11','age':23}
{birthday':'1989-11-17','age':29}
document | age | birthday |
---|---|---|
doc1 | 23 | 1985-11-11 |
doc2 | 29 | 1989-11-17 |
存储在磁盘上,节省内存
对排序、分组和一些聚合操作能够大大提升性能
注意:默认对不分词的字段是开启的,对分词字段无效(需要把fielddata置为true)
doc_values:false 关闭正排索引
//
DELETE test1
#创建mapping
PUT /test1
{
"mappings": {
"properties": {
"age" : {"type" : "long","doc_values":false}, #doc_values 关闭正排索引
"birthday" : {"type" : "date","index": false},
"name" : {"type" : "text"}
}
}
}
#数据1
PUT /test1/_doc/1
{
"age":10,
"birthday":"2019-09-23",
"name":"xiaochao"
}
#数据2
PUT /test1/_doc/2
{
"age":20,
"birthday":"2019-02-23",
"name":"xiaoyi"
}
#数据3
PUT /test1/_doc/3
{
"age":30,
"birthday":"2019-07-23",
"name":"xiaofei"
}
#查询结果报错
GET /test1/_search
{
"query":{
"match_all": {}
},
"sort": [
{
"age": {
"order": "asc"
}
}
]
}