elasticsearch基本概念与查询

推荐书籍:
Elasticsearch: 权威指南

基本概念

1、Cluster(集群)

es集群对外提供索引和搜索的服务,其包含一个或者多个节点,每个节点都有统一的集群名称。参考本地集群搭建。

2、Node(节点)

单独一个Elasticsearch服务器实例称为一个node,node是集群的一部分,每个node有独立的名称,默认是启动时获取一个UUID作为名称,也可以自行配置。

3、Shard(分片)

Shard分片也称为primary shard,是单个Lucene索引,由于单台机器的存储容量是有限的,而Elasticsearch索引的数据可能特别大,单台机器无法存储全部数据,就需要将索引中的数据切分为多个shard,分布在多台服务器上存储。利用shard可以很好地进行横向扩展,存储更多数据,让搜索和分析等操作分布到多台服务器上去执行,提升集群整体的吞吐量和性能。创建索引时就应该预估好需要的分片数量,一旦创建则分片数量无法更改。

4、Replica(复制分片)

replica全称叫replica shard,是索引的副本,完全拷贝shard的内容,shard与replica的关系可以是一对多,同一个shard可以有一个或多个replica。当集群中有节点宕机了,丢失的shard会由replica补位,保证数据高可用;replica shard也能分担查询请求,提升集群的吞吐量。

5、Index(索引)

es索引,其保存具有相同结构的文档集合,类似于关系型数据库的数据库实例(6.0.0版本type废弃后,索引的概念下降到等同于数据库表的级别)。一个集群里可以定义多个索引

6、Type(类型)

类型,原本是在索引(Index)内进行的逻辑细分,但后来发现企业研发为了增强可阅读性和可维护性,制订的规范约束,同一个索引下很少还会再使用type进行逻辑拆分(如同一个索引下既有订单数据,又有评论数据),因而在6.0.0版本之后,此定义废弃。

7、Document(文档)

Elasticsearch最小的数据存储单元,JSON数据格式,类似于关系型数据库的表记录(一行数据),结构定义多样化,同一个索引下的document,结构尽可能相同。

8、Field type(字段类型)
  • text:被分析索引的字符串类型
  • keyword:不能被分析,只能被精确匹配的字符串类型
  • date:日期类型,可以配合format一起使用
  • long:长整型,数字类型
  • integer:整型,数字类型
  • short:短整型,数字类型
  • double:双精度浮点型,数字类型
  • Boolean:布尔型,true、false
  • array:数组类型
  • object:对象类型,json嵌套
  • ip:ip类型
  • geo_point:地理位置类型
9、分词器

ElasticSearch借助各种类型的分词器来对文档内容进行分词处理,以便于创建倒排索引,这是搜索的核心。同时也对搜索内容进行分词处理,用以在倒排索引中索引文档。

1、内置分词器

标准分词器(standard analyzer)(默认)

  • 分析过程:字符过滤器->字符处理->分词过滤(分词转换)
    说明:首先是字符过滤器过滤掉特殊符号以及量词(the、an、a等),进一步将分词小写处理,

英文分词器(english analyzer)

  • 分析过程:字符过滤器->字符处理->分词过滤(分词转换,词干转化)

说明:首先是字符过滤器过滤掉特殊符号以及量词(the、an、a等),进一步将分词小写处理,再次进行分词转换,例如:eating -> eat,其实它们两是一回事。

简单分词器(simple analyzer)

  • 先按照空格分词,英文大写转小写。

空格分词器(whitespace analyzer)

  • 先按照空格分词,英文不做大小写处理。
2、外部分词器
中文分词器(ik_maxword)

会将文本做最细粒度的拆分;尽可能多的拆分出词语,例如:如南京市长江大桥 --> 南京市/南京/市长/长江大桥/长江/大桥

中文分词器(ik_smart)

会做最粗粒度的拆分;已被分出的词语将不会再次被其它词语占有,如南京市长江大桥 --> 南京市/长江大桥

10、评分规则
  • TF(token frequency):词频,文档中出现分词的数量,出现次数越多,相关性越强。
  • IDF(inverse document frequency):逆向文档频率,包含分词的文档数量相关,包含分词的文档数量越多则表明相关性越弱。
  • TFNORM(token frequency normalize):词频规格化,根据field长度做归一化,文档内出现频率越高,field越短相关性越强。
11、倒排索引与正排索引

ElasticSearch除了强大的搜索功能外,还可以支持排序、聚合之类的操作,搜索需要用到倒排索引,可以高效的通过分词索引到对应的文档,但是对于排序、聚合等操作,倒排索引就显得吃力低效了,此时正排索引就派上用场了,正排索引使得ElasticSearch高效的进行排序、聚合操作。

1、倒排索引

倒排索引包含两个部分,单词词典和倒排列表。

单词词典

单词词典(Term Dictionary)记录所有文档的单词,记录单词到倒排列表的关联关系。单词词典比较大,可以通过 B + 树 或者 哈希拉链法实现,以满足高性能的插入与查询

倒排列表

倒排列表(Postion List)记录了单词对应的文档结合,由倒排索引项组成(文档ID、词频TF、偏移)

2、正排索引

基于文档维度的,建立文档与字段值的映射关系。

documentagebirthday
doc1181994-10-14
doc2201985-06-04
doc_values与fielddata

在ElasticSearch中,doc_values和fielddata就是用来给文档建立正排索引的。他俩一个很显著的区别是,前者的工作地盘主要在磁盘,而后者的工作地盘在内存。

维度doc_valuefielddata
创建时间创建索引时创建使用时动态创建
创建位置磁盘内存(jvm heap)
优点节约内存空间节约磁盘空间
缺点索引速度稍低文档越多,耗费内存越大,有oom的风险

说明:ElasticSearch对于非分词字段,默认doc_value是开启的,如果非常确定某个字段将来不会用来排序或者聚合操作,可以显示地指定关闭doc_value;对于分词字段,如果未将fielddata显示开启,则对于分词字段的排序、聚合操作将会报错。开启fielddata需要慎重,因为开销是昂贵的,还有oom风险

基本语法

基本查询(Query查询)
数据准备
PUT /lib3
{
    "settings":{
    "number_of_shards" : 3,
    "number_of_replicas" : 0
    },
     "mappings":{
      "user":{
        "properties":{
            "name": {"type":"text"},
            "address": {"type":"text"},
            "age": {"type":"integer"},
            "interests": {"type":"text"},
            "birthday": {"type":"date"}
        }
      }
     }
}

GET /lib3/user/_search?q=name:lisi

GET /lib3/user/_search?q=name:zhaoliu&sort=age:desc
term查询和terms查询

term query会去倒排索引中寻找确切的term,它并不知道分词器的存在。这种查询适合keyword 、numeric、date。

term:查询某个字段里含有某个关键词的文档

GET /lib3/user/_search/
{
  "query": {
      "term": {"interests": "changge"}
  }
}

terms:查询某个字段里含有多个关键词的文档

GET /lib3/user/_search
{
    "query":{
        "terms":{
            "interests": ["hejiu","changge"]
        }
    }
}
控制查询返回的数量

from:从哪一个文档开始
size:需要的个数

GET /lib3/user/_search
{
    "from":0,
    "size":2,
    "query":{
        "terms":{
            "interests": ["hejiu","changge"]
        }
    }
}
返回版本号
GET /lib3/user/_search
{
    "version":true,
    "query":{
        "terms":{
            "interests": ["hejiu","changge"]
        }
    }
}
match查询

match query知道分词器的存在,会对filed进行分词操作,然后再查询

GET /lib3/user/_search
{
    "query":{
        "match":{
            "name": "zhaoliu"
        }
    }
}

GET /lib3/user/_search
{
    "query":{
        "match":{
            "age": 20
        }
    }
}

match_all:查询所有文档

GET /lib3/user/_search
{
  "query": {
    "match_all": {}
  }
}

multi_match:可以指定多个字段

GET /lib3/user/_search
{
    "query":{
        "multi_match": {
            "query": "lvyou",
            "fields": ["interests","name"]
         }
    }
}

match_phrase:短语匹配查询

ElasticSearch引擎首先分析(analyze)查询字符串,从分析后的文本中构建短语查询,这意味着必须匹配短语中的所有分词,并且保证各个分词的相对位置不变:

GET lib3/user/_search
{
  "query":{  
      "match_phrase":{  
         "interests": "duanlian,shuoxiangsheng"
      }
   }
}
指定返回的字段
GET /lib3/user/_search
{
    "_source": ["address","name"],
    "query": {
        "match": {
            "interests": "changge"
        }
    }
}
控制加载的字段
GET /lib3/user/_search
{
    "query": {
        "match_all": {}
    },
    

    "_source": {
          "includes": ["name","address"],
          "excludes": ["age","birthday"]
      }

}

使用通配符*

GET /lib3/user/_search
{
    "_source": {
          "includes": "addr*",
          "excludes": ["name","bir*"]
        

    },
    "query": {
        "match_all": {}
    }

}
排序

使用sort实现排序:
desc:降序,asc升序

GET /lib3/user/_search
{
    "query": {
        "match_all": {}
    },
    "sort": [
        {
           "age": {
               "order":"asc"
           }
        }
    ]
        
}

GET /lib3/user/_search
{
    "query": {
        "match_all": {}
    },
    "sort": [
        {
           "age": {
               "order":"desc"
           }
        }
    ]
        
}
前缀匹配查询
GET /lib3/user/_search
{
  "query": {
    "match_phrase_prefix": {
        "name": {
            "query": "zhao"
        }
    }
  }
}
范围查询

range:实现范围查询

参数:from,to,include_lower,include_upper,boost

include_lower:是否包含范围的左边界,默认是true

include_upper:是否包含范围的右边界,默认是true

GET /lib3/user/_search
{
    "query": {
        "range": {
            "birthday": {
                "from": "1990-10-10",
                "to": "2018-05-01"
            }
        }
    }
}


GET /lib3/user/_search
{
    "query": {
        "range": {
            "age": {
                "from": 20,
                "to": 25,
                "include_lower": true,
                "include_upper": false
            }
        }
    }
}
wildcard查询

允许使用通配符* 和 ?来进行查询

*代表0个或多个字符

?代表任意一个字符

GET /lib3/user/_search
{
    "query": {
        "wildcard": {
             "name": "zhao*"
        }
    }
}


GET /lib3/user/_search
{
    "query": {
        "wildcard": {
             "name": "li?i"
        }
    }
}
fuzzy实现模糊查询

value:查询的关键字

boost:查询的权值,默认值是1.0

min_similarity:设置匹配的最小相似度,默认值为0.5,对于字符串,取值为0-1(包括0和1);对于数值,取值可能大于1;对于日期型取值为1d,1m等,1d就代表1天

prefix_length:指明区分词项的共同前缀长度,默认是0

max_expansions:查询中的词项可以扩展的数目,默认可以无限大

GET /lib3/user/_search
{
    "query": {
        "fuzzy": {
             "interests": "chagge"
        }
    }
}

GET /lib3/user/_search
{
    "query": {
        "fuzzy": {
             "interests": {
                 "value": "chagge"
             }
        }
    }
}
高亮搜索结果
GET /lib3/user/_search
{
    "query":{
        "match":{
            "interests": "changge"
        }
    },
    "highlight": {
        "fields": {
             "interests": {}
        }
    }
}
Filter查询

filter是不计算相关性的,同时可以cache。因此,filter速度要快于query。

POST /lib4/items/_bulk
{"index": {"_id": 1}}

{"price": 40,"itemID": "ID100123"}

{"index": {"_id": 2}}

{"price": 50,"itemID": "ID100124"}

{"index": {"_id": 3}}

{"price": 25,"itemID": "ID100124"}

{"index": {"_id": 4}}

{"price": 30,"itemID": "ID100125"}

{"index": {"_id": 5}}

{"price": null,"itemID": "ID100127"}
简单的过滤查询
GET /lib4/items/_search
{ 
       "post_filter": {
             "term": {
                 "price": 40
             }
       }
}


GET /lib4/items/_search
{
      "post_filter": {
          "terms": {
                 "price": [25,40]
              }
        }
}

GET /lib4/items/_search
{
    "post_filter": {
        "term": {
            "itemID": "ID100123"
          }
      }
}

查看分词器分析的结果:

GET /lib4/_mapping

不希望商品id字段被分词,则重新创建映射

DELETE lib4

PUT /lib4
{
    "mappings": {
        "items": {
            "properties": {
                "itemID": {
                    "type": "text",
                    "index": false
                }
            }
        }
    }
}
bool过滤查询

可以实现组合过滤查询

格式:

{
“bool”: {
“must”: [],
“should”: [],
“must_not”: []
}
}

must:必须满足的条件—and

should:可以满足也可以不满足的条件–or

must_not:不需要满足的条件–not

GET /lib4/items/_search
{
    "post_filter": {
          "bool": {
               "should": [
                    {"term": {"price":25}},
                    {"term": {"itemID": "id100123"}}
                   

                  ],
                "must_not": {
                    "term":{"price": 30}
                   }
                       
                }
             }

}

嵌套使用bool:

GET /lib4/items/_search
{
    "post_filter": {
          "bool": {
                "should": [
                    {"term": {"itemID": "id100123"}},
                    {
                      "bool": {
                          "must": [
                              {"term": {"itemID": "id100124"}},
                              {"term": {"price": 40}}
                            ]
                          }
                    }
                  ]
                }
            }
}
2.8.3 范围过滤

gt: >

lt: <

gte: >=

lte: <=

GET /lib4/items/_search
{
     "post_filter": {
          "range": {
              "price": {
                   "gt": 25,
                   "lt": 50
                }
            }
      }
}
2.8.5 过滤非空
GET /lib4/items/_search
{
  "query": {
    "bool": {
      "filter": {
          "exists":{
             "field":"price"
         }
      }
    }
  }
}

GET /lib4/items/_search
{
    "query" : {
        "constant_score" : {
            "filter": {
                "exists" : { "field" : "price" }
            }
        }
    }
}
2.8.6 过滤器缓存

ElasticSearch提供了一种特殊的缓存,即过滤器缓存(filter cache),用来存储过滤器的结果,被缓存的过滤器并不需要消耗过多的内存(因为它们只存储了哪些文档能与过滤器相匹配的相关信息),而且可供后续所有与之相关的查询重复使用,从而极大地提高了查询性能。

注意:ElasticSearch并不是默认缓存所有过滤器,
以下过滤器默认不缓存:

numeric_range
script
geo_bbox
geo_distance
geo_distance_range
geo_polygon
geo_shape
and
or
not

exists,missing,range,term,terms默认是开启缓存的

开启方式:在filter查询语句后边加上
“_catch”:true

聚合查询
(1)sum

GET /lib4/items/_search
{
  "size":0,
  "aggs": {
     "price_of_sum": {
         "sum": {
           "field": "price"
         }
     }
  }
}

(2)min

GET /lib4/items/_search
{
  "size": 0, 
  "aggs": {
     "price_of_min": {
         "min": {
           "field": "price"
         }
     }
  }
}

(3)max

GET /lib4/items/_search
{
  "size": 0, 
  "aggs": {
     "price_of_max": {
         "max": {
           "field": "price"
         }
     }
  }
}

(4)avg

GET /lib4/items/_search
{
  "size":0,
  "aggs": {
     "price_of_avg": {
         "avg": {
           "field": "price"
         }
     }
  }
}

(5)cardinality:求基数

GET /lib4/items/_search
{
  "size":0,
  "aggs": {
     "price_of_cardi": {
         "cardinality": {
           "field": "price"
         }
     }
  }
}

(6)terms:分组

GET /lib4/items/_search
{
  "size":0,
  "aggs": {
     "price_group_by": {
         "terms": {
           "field": "price"
         }
     }
  }
}

对那些有唱歌兴趣的用户按年龄分组
GET /lib3/user/_search
{
  "query": {
      "match": {
        "interests": "changge"
      }
   },
   "size": 0, 
   "aggs":{
       "age_group_by":{
           "terms": {
             "field": "age",
             "order": {
               "avg_of_age": "desc"
             }
           },
           "aggs": {
             "avg_of_age": {
               "avg": {
                 "field": "age"
               }
             }
           }
       }
   }
}

2.10 复合查询

将多个基本查询组合成单一查询的查询

2.10.1 使用bool查询

接收以下参数:

must:
文档 必须匹配这些条件才能被包含进来。

must_not:
文档 必须不匹配这些条件才能被包含进来。

should:
如果满足这些语句中的任意语句,将增加 _score,否则,无任何影响。它们主要用于修正每个文档的相关性得分。

filter:
必须 匹配,但它以不评分、过滤模式来进行。这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档。

相关性得分是如何组合的。每一个子查询都独自地计算文档的相关性得分。一旦他们的得分被计算出来, bool 查询就将这些得分进行合并并且返回一个代表整个布尔操作的得分。

下面的查询用于查找 title 字段匹配 how to make millions 并且不被标识为 spam 的文档。那些被标识为 starred 或在2014之后的文档,将比另外那些文档拥有更高的排名。如果 两者 都满足,那么它排名将更高:

{
    "bool": {
        "must": { "match": { "title": "how to make millions" }},
        "must_not": { "match": { "tag":   "spam" }},
        "should": [
            { "match": { "tag": "starred" }},
            { "range": { "date": { "gte": "2014-01-01" }}}
        ]
    }
}

如果没有 must 语句,那么至少需要能够匹配其中的一条 should 语句。但,如果存在至少一条 must 语句,则对 should 语句的匹配没有要求。
如果我们不想因为文档的时间而影响得分,可以用 filter 语句来重写前面的例子:

{
    "bool": {
        "must": { "match": { "title": "how to make millions" }},
        "must_not": { "match": { "tag":   "spam" }},
        "should": [
            { "match": { "tag": "starred" }}
        ],
        "filter": {
          "range": { "date": { "gte": "2014-01-01" }} 
        }
    }
}

通过将 range 查询移到 filter 语句中,我们将它转成不评分的查询,将不再影响文档的相关性排名。由于它现在是一个不评分的查询,可以使用各种对 filter 查询有效的优化手段来提升性能。

bool 查询本身也可以被用做不评分的查询。简单地将它放置到 filter 语句中并在内部构建布尔逻辑:

{
    "bool": {
        "must": { "match": { "title": "how to make millions" }},
        "must_not": { "match": { "tag":   "spam" }},
        "should": [
            { "match": { "tag": "starred" }}
        ],
        "filter": {
          "bool": { 
              "must": [
                  { "range": { "date": { "gte": "2014-01-01" }}},
                  { "range": { "price": { "lte": 29.99 }}}
              ],
              "must_not": [
                  { "term": { "category": "ebooks" }}
              ]
          }
        }
    }
}
constant_score查询

它将一个不变的常量评分应用于所有匹配的文档。它被经常用于你只需要执行一个 filter 而没有其它查询(例如,评分查询)的情况下。

{
    "constant_score":   {
        "filter": {
            "term": { "category": "ebooks" } 
        }
    }
}

term 查询被放置在 constant_score 中,转成不评分的filter。这种方式可以用来取代只有 filter 语句的 bool 查询。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

四美

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值