Elasticsearch学习(2) 基本概念

目录

1、Es基本定义

1.1 文档(Document)

1.2 索引(Index)

1.3 类型(Type)

1.4 映射(Mapping)

1.5 集群(Cluster)

1.6 节点(Node)

1.7 分片(Shard)

1.8 分段

2、索引

2.1 索引新数据

2.2 搜索数据

2.4 过滤器

3 分析数据

3.1 发生时机

3.2  过程

3.3 用Api分析文本数据

3.4 内置的分析器

4 相关性运算

4.1 如何打分

4.2 boosting

4.3 function_score

4.5 字段数据(FieldData)

5 聚集

 5.1 度量聚集

5.2 多桶型聚集


1、Es基本定义

1.1 文档(Document)

    Es 是面向文档的,文档是所有可搜索数据的最小单位。它对应关系型数据库中的表里的一条数据。

1.2 索引(Index)

    索引简单来说就是相似结构文档的集合,索引有一个名称,一个索引可以包含很多文档,一个索引就代表了一类类似的或者相同的文档,比如说建立一个商品索引,里面可能就存放了所有的商品数据,也就是所有的商品文档。每一个索引都是自己的 Mapping 定义文件,用来去描述去包含文档字段的类型,分片(Shard)体现的是物理空间的概念,索引中的数据分散在分片上
    在Es 7.0版本以前,我理解索引对应的应该是数据库里的表,表里有一个type字段来定义不同的类型数据。每个类型可以支持多或少的字段。
    但是更多人为了方便理解认为Index 是数据库,每个Type对应的是数据库里的表。但是细想这样不太合理。这个涉及到索引的映射,后面说。

1.3 类型(Type)

    在 7.0 之前,每一个索引是可以设置多个 Types 的,每个 Type 会拥有相同结构的文档,但是在 6.0 开始,Type 已经被废除,在 7.0 开始,一个索引只能创建一个 Type,也就是 _doc。每个索引里都可以有一个或多个 Type,Type 是索引中的一个逻辑数据分类,一个 Type 下的文档,都有相同的字段

        为什么要取消type?
同一个Index下的不同实体(不同type意味着field往往不一样,可称为不同实体)太多,且分布稀疏不均,严重干扰了Lucene压缩文档的能力,所以在彻底抛弃type之后,ES的存储能力将会有所提高。
 
所以ES给type制定了消亡路线:
type在6.x中只能有一个,可自定义。
type在7.x中只能有一个,且只能是_doc。
type在8.x(未来版本)彻底取消,API会大变,以前的<INDEX>/<TYPE>/<DOC>的方式会变成<INDEX>/<DOC>

1.4 映射(Mapping)

     每个索引都可以对字段做类型的定义,这个过程就是映射。映射就相当于数据库中我们去定义字段的类型。

     映射包括了该类型的文档中可能出现的所有字段,并告诉Es如果索引一个文档内的多个字段。

1.5 集群(Cluster)

1.6 节点(Node)

    节点其实就是一个 ES 实例,本质上是一个 Java 进程,一台机器上可以运行多个 ES 进程,但是生产环境一般建议一台机器上只运行一个 ES 实例。

    每一个节点都有自己的名字,节点名称很重要(在执行运维管理操作的时候),可以通过配置文件进行配置,或者启动的时候 -E node.name=node1 指定。每一个节点在启动之后,会分配一个 UID,保存在 data 目录下。

1.7 分片(Shard)

    由于单台机器无法存储大量数据,ES 可以将一个索引中的数据切分为多个分片(Shard),分布在多台服务器上存储。有了分片就可以横向扩展,存储更多数据,让搜索和分析等操作分布到多台服务器上去执行,提升吞吐量和性能。
    索引与分片的关系,一个 ES 索引包含很多分片,一个分片是一个 Lucene 的索引,它本身就是一个完整的搜索引擎,可以独立执行建立索引和搜索任务。Lucene 索引又由很多分段组成,每个分段都是一个倒排索引。 ES 每次 refresh 都会生成一个新的分段,其中包含若干文档的数据。在每个分段内部,文档的不同字段被单独建立索引。每个字段的值由若干词(Term)组成,Term 是原文本内容经过分词器处理和语言处理后的最终结果(例如,去除标点符号和转换为词根)。

分片分为两类,一类为主分片(Primary Shard),另一类为副本分片(Replica Shard)

    主分片主要用以解决水平扩展的问题,通过主分片,就可以将数据分布到集群上的所有节点上,一个主分片就是一个运行的 Lucene 实例,当我们在创建 ES 索引的时候,可以指定分片数,但是主分片数在索引创建时指定,后续不允许修改,除非使用 Reindex 进行修改。

    副本分片用以解决数据高可用的问题,也就是说集群中有节点出现硬件故障的时候,通过副本的方式,也可以保证数据不会产生真正的丢失,因为副本分片是主分片的拷贝,在索引中副本分片数可以动态调整,通过增加副本数,可以在一定程度上提高服务查询的性能(读取的吞吐)。

 

1.8 分段

    elasticsearch 中每个索引都会创建一个到多个分片和零个到多个副本,这些分片或副本实质上都是lucene索引。

    lucene索引是基于多个索引段创建,索引文件中绝大部分数据都是只写一次,读多次,而只有用于保存文档删除信息的文件才会被多次更改

2、索引

2.1 索引新数据

    当一个创建新索引的请求被打到Es集群中的某个节点后,该节点首先选择文档要被索引到哪个分片。默认情况下,文档会在分片中均匀的分布:对于每片文档,分片是通过文档的Id字符串进行计算决定的。如果没有指定id,则会自动生成id,并hash后到指定分片存储。

分片确定后,接收请求的节点将文档转发到该分片所在的节点,并将数据写入到该分片,以及该分片的副本。等所有分片和副本分片完成后,会返回成功。

 

2.2 搜索数据

    搜索的时候,接受请求的节点将请求转发到一组包含所有数据的分片。Es使用轮询机制选择可用的分片,并将搜索转发过去

    怎么决定哪个分片:

  •  搜索条件有id:任意连上一个Es节点,然后根据hash这个id找到对应的分片,该分片可能是主分片也可能是副本分片。
  • 全文检索:任意连上一个Es节点,然后向所有的分片发起关键字查询,其他节点把数据返回到当前节点并进行汇总

2.4 过滤器

    过滤器和查询类似,但是它们在评分机制和搜索行为的性能上,有所不同。

    查询会为特定的词条进行计算得分,搜索的过滤器只是会返回 文档是否匹配过滤条件,不会评分,只是简单的是与否。

 

由于这个差异,过滤器比普通查询更快,而且还可以被缓存。

3 分析数据

3.1 发生时机

     分析过程是文档被发到Es节点后,节点在创建倒排索引之前会先对数据进行分析。对哪个字段进行分析是可以进行定制对,在进行索引mapping设置时,可以指定字段是否需要进行分析。

3.2  过程

    标准分析步骤如下:

  • 字符过滤:使用字符过滤器转变字符
  • 文本切分分词:将文本切分为单个或多个分词
  • 分词过滤:使用分词过滤器转变每个分词   

3.3 用Api分析文本数据

3.3.1 analyze Api

    下面我是用的自己安装的一个ik分词器插件进行的分析

3.3.2 term Vectors api

 设置term_statistics=true 后将返回:
    total term frequency, 一个term在所有document中出现的频率;
    document frequency,有多少document包含这个term
设置field_statistics=true 后将返回:
    document count: 有多少document包含这个field;
    sum of document frequency:一个field中所有term的df之和;
    sum of total term frequency:一个field中的所有term的tf之和

 

3.4 内置的分析器

4 相关性运算

     做搜索查询,除了要考虑我的搜索条件能匹配到哪些文档,还要考虑文档的相关性匹配。

     相关性就是对于某个查询而言,文档A比文档B匹配度更高,更精确。

     在Es中确定文档和查询有多么相关的过程被称为打分(scoring)。

4.1 如何打分

   4.1.1 词频(TF)

    考虑给一篇文档打分的首要方式,是查看一个词条在文本中出现的次数。

    例:

        "我们都是中国人"

        "中国人爱中国人"   

     上面的 "中国人" 在两个句子都出现了,第一句出现了1次,第二句出现了2次。所以第一句 词频是1,第二句词频是2,第二句得分更高

    4.1.2 逆文档频率(IDF)

    比文档词频稍微复杂一点的是逆文档。如果一个分词在索引的不同文档中出现越多的次数,那么它就越不重要。

    

    1和2 结合起来可以称为TF-IDF 评分方法。

    4.1.3 Okapi BM25

     BM25是Lucene中第二流行的评分方法,仅次于TF-IDF。它是概率性的相关性算法,这意味着分数可以认为是给文档和查询匹配的概率。

相关评分算法参考:  https://segmentfault.com/a/1190000019630099?utm_source=tag-newest

4.2 boosting

  •  boosting是一个可以用来修改文档的相关性的设置。
  •  boosting有两种设置方式,1、可以在建立时,在mapping下的字段设置处设置

                                                   2、在查询时

    推荐在查询时进行动态的设置,这样更灵活,允许随时更改。

    4.2.1 boost如何计算

        boost的数值并不是精确的乘数。在计算分数的时候boost数值是被标准计算的。

    例如:如果为每个字段指定了10的boost,那么最终计算后每个字段会获得1的值。

            设置的时候应该考虑的是相对的值,比如 单独将某一个字段的boost设置为3,那么这个字段的重要性就是比其他字段大 3倍

   4.2.2 mapping时设置boosting

        

4.2.3 查询时设置boost

下面是给所有字段设置了 3

4.3 function_score

    function_score查询允许用户指定任何数量的任意函数,让他们作用于匹配了初识查询的文档,修改得分,达到精细化控制结果相关性的目的。

    function_score 查询 | Elasticsearch: 权威指南 | Elastic

    4.3.1 weight函数

        weight是最简单的function函数,它将得分乘以一个常数。之前提到的boost字段是按照对比其他字段的标准来打分。weight是会真正的乘以确定的数值。

 不用weight函数

使用functions weight函数: 

4.3.2  field_value_factor

      有时候我们希望使用文档中的某些数据来增加分数。field_value_factor函数将包含数值的字段的名称作为输入,选择性的将其值乘以常数,然后最终对其运用数学函数。

      直接查询:

4.5 字段数据(FieldData)

    当你希望查询一个词条并获取匹配的文档时,目前我们应用的都是倒排索引。但是当需要在某个字段上进行排序或者用一些字段做聚集时,Es需要知道你的排序或者聚集字段在文档中的确切值。

    

  •  字段数据缓存就是将字段数据加载到缓存里,这是进行快速排序或者聚集的实现方式,但是由此也会带来一个问题,当文档太多时,会消耗大量的内存。
  •  DocValues不支持索引(anaylyzed)字段,FieldData支持text类型字段。FieldData默认不开启,想要开启,需要在映射时配置开启
  • FieldData会很消耗jvm的内存,容易造成OOM。所以设计时应该用 text索引字段用于全文检索,其他字段使用DocValues方式进行排序,聚合。

5 聚集

    聚集可以理解为分类统计,比如 对一组文档的某个词条进行计数,或者计算某个数值型字段的平均值

 5.1 度量聚集

    5.1.1 统计数据

    简单统计,包括 avg,max,min,sum 等只会输出一个结果

5.2 多桶型聚集

    Bucket可以理解为一个桶,它会遍历文字中的内容,凡事符合某一要求的就放在一个桶中,分桶相当于sql中的group by。

5.2.1 terms聚集

        根据某一项的每个唯一的值来聚合

  • Es为了拿到排序后前n个词条,会必须从每个分片获取一定数量的词条(可以通过参数shard_size设置)并且将结果聚集

        这种机制意味着对于某些未能在单个分片上排名靠前的词条,可能会得到不正确的技术,可以通过shard_size调整,但是这样带来的结果 就是可能实现聚集操作会比较耗时间和资源。

5.2.2 range聚集

     就是范围的聚集

"aggs": {
    "prices_range": {
      "range": {
        "field": "price",
        "ranges": [
          {
            "key": "<50000", 
            "to":50000
          },
          {
            "key": "50000~80000", 
            "from": 50000,
            "to": 80000
          },
          {
            "key": ">80000", 
            "from": 80000
          }
        ]
      }
    }
  }

5.2.3 histogram聚集

    为了处理数值型的范围,还可以使用histogram聚集。这个聚集和range聚集很像,range聚集是需要定义一个个的范围。而histogram是定义一个固定的间距,Es会根据字段的所有值为你自动构建多个范围。

    5.2.3.1 普通 histogram聚集

{
  "aggs": {
    "num_histogram": {
      "histogram": {
        "field": "num",
        "interval": 2
      }
    }
  }
}

5.2.3.1 Date Histogram    

    这个是针对时间格式数据的直方图聚合

{
  "aggs": {
    "sales_over_time": {
      "date_histogram": {
        "field": "sellTime",
        "interval": "month",
        "format": "yyyy-MM-dd"
      }
    }
  }
}

参考:

        Elasticsearch实战

        各种网络博文


版权声明:本文为qGANG原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。