ElasticSearch(ES)知识积累

    由于工作中接触到了ES,并且惊喜的发现具有很好的性能,所以特意对其相关知识点进行总结,参考了很多网上大神的总结,这里主要是加深自己对es的了解。

1.简介

    ES是基于lucene的构建的高扩展的分布式全文检索引擎,可以做到近乎实时的存储,全文检索。

注:Lucene 是 apache 下的一个开放源代码的全文检索引擎工具包,提供了完整的查询引擎和索引引擎,部分文本分析引擎

2.主要概念

集群cluster                

es是分布式全文检索引擎,可以由多台服务器组成,它们的集合即es集群。

节点node 每一个服务器,即es节点。
分片shard

当文档的数据较大的时候,单个节点的内存或者磁盘不足,需要多个节点,可以将数据切分成多个分片,然后分布在不同的节点上。

分片作用:

1.能够水平扩展容量。

2.使得各个分片能够分布式,并行操作,提高性能。

副本replia

每一个分片可以有零个或一个以上的副本,每一个副本是分片的完整复制。

副本作用:

1.备用,当主分片失效后,副本将升级为主分片,提高可用性。

2.当大量并发请求时,提高es负载能力,实现高吞吐量(可以理解为多一套可以查询到库)

接下来的基本概念通过与传统数据进行比对,大家应该就比较好理解了

ES 传统数据库
Index 索引 database 数据库
type 类型 table 表
document 文档 row 行
field 字段 column 列名
mapping 映射 schema 表结构
es会对每个词建索引            index 索引                               

3.倒排索引

    说到ES,我们不得不提到倒排索引了,这个应该是es为什么在全文检索中这么强大的重要因素了。

    假设有一篇文档,文档为id,文档中有很多单词。传统数据库,先找到该文档,然后在该文档中查看有哪些单词。倒排索引正好相反,采用的是,单词->文档 的模式,文档中的所有单词为索引,通过单词直接定位到文档。

例如:

1.我们都是好孩子。

2.今天天气特别好。

3.我们好孩子比他们孩子多。

转化成倒排索引就是

我们    1,3
都是    1
好      1,2,3
今天    2
天气    2
特别    2
孩子    1,3
他们    3
多      3

事实上,倒排索引还记录了,单词在文档中出现的位置以及词频。

我们    (1,1,1),(3,1,1)
都是    (1,1,2)
好      (1,1,3),(2,1,4),(3,1,2)
今天    (2,1,1)
天气    (2,1,2)
特别    (2,1,3)
孩子    (1,1,4),(3,2,<3,6>)
他们    (3,1,5)
多      (3,1,7)
比如孩子的
(3,2,<3,6>)

表示出现在文档3,2次,同时第3个和第6个位置出现(这里的位置指的是词的位置)

当我们将数据导入到es,es便开始按照倒排索引建立索引。

4.工作使用到的知识点

    前面我们主要介绍了es的主要概念,这一节就比较零碎了,主要记录工作中使用到的es的相关知识点。

4.1.string字段的index属性

    工作中的,我的字段类型都是string,但是根据具体业务逻辑,有些需要分词有些不需要分词。

"Std_Typ": {
          "index": "not_analyzed",
          "type": "string"
        },
 "Seg_Nm": {
          "analyzer": "ik_max_word",
          "type": "string"

        }

比如上面的两个字段,其中第一个表示不分词,第二个表示分词,同时按照ik分词(es默认的string类型都是会分词的,但是中文的分词是每个字一个,不适合)

    这里我们就重点提一下,字段的string的index属性设置

(1)analyzed

先分词,再索引

(2)not_analyzed

不分词,直接索引

(3)no

不索引该字段,也不会被搜出来

4.2.ES存储方式

    上面提到了string类型,这里就讲讲es的存储方式。

    当我们通过此条对es进行文档搜索对时候,利用的是es的倒排索引,但是当我们进行排序或者聚合的时候,正好相反,是先找到文档,查找文档中的词条,es采用的列式存储来进行排序和聚合的。

   文档值(doc_value)数据结构是列式存储风格的结构。默认情况下,es中除了字符类型的分析字段外,其他字段都会启用文档值,存储在硬盘中。该默认值可以改变,节省硬盘空间。

    如果字符类型分析字段想要进行排序或者聚合怎么办呢,还有一个顺排索引(fielddata),这个是将词条-文档 转化成 文档-词条,存在在jvm的堆内存中。

所有字段 倒排序索引(硬盘)
除了字符类型分析字段外的所有字段(默认)  文档值(doc_value)(硬盘)                      

字符类型分析字段(排序或者聚合)(默认) 顺序索引(fielddata)(内存)                 

    具体的说明大家可以参考这篇博客,写的很详细 https://www.cnblogs.com/ljhdo/p/5016852.html

4.3.ES评分机制

    我在该项目中一开始想到的是用es的评分机制,虽然最后放弃了,因为打分后,还要取前3000条数据,涉及到了es的评分以及排序,都是比较耗时的操作,但是这里还是简单记录了一下es的评分机制。

    这里评分核心主要采用的是 TF/IDF

(1)TF

词频,词在文档中出现的次数越多,那么分数越高

(2)IDF

逆向文档频率,词在所有文档出现的频率,频率越高,说明该词越不重要,比如and,or等,分数越低,反之越高。

(3)文档长度归一长度

当词所在的文档越短,分数越高,反之越低。比如“开心”这个词在A今天我很开心B今天我非常的开心呢因为我带着我的小女友去迪斯尼溜达了,很明显A的分数高于B

    具体的可以参考该博客 https://blog.csdn.net/paditang/article/details/79098830

    这些都是大神呀。

4.4.ES缓存机制

    上一节说到,评分这个方案放弃后,我最后采用的是filter的方式,利用了ES的缓存机制,从原来每条查询时间1~2s,直接降到了几十毫秒的速度。这里简单说明一下es的缓存机制中的filer。

    Filter Cache,它的作用就是对一个查询中包含的过滤器执行结果进行缓存。比如我们常用的term,terms,range过滤器都会在满足某种条件后被缓存,bool过滤器包含的子query clause会被缓存。

   

GET _search
{
  "query": { 
    "bool": { 
      "must": [
        { "match": { "title":   "Search"        }}, 
        { "match": { "content": "Elasticsearch" }}  
      ],
      "filter": [ 
        { "term":  { "status": "published" }}, 
        { "range": { "publish_date": { "gte": "2015-01-01" }}} 
      ]
    }
  }
}

    上面是别人的例子,在我自己项目中,第一次查询可能呀几百毫秒,但是到了后面,如果有相同的filter,就只要几十毫秒甚至几秒(在5000W+的数据中搜索),是越来越快的感觉。

    过滤器缓存是可以设置, indices.cache.filter.size ,该属性的默认值 20%。

4.5.match,match_phrase,term的区别

    这三者也是工作中用到的。

    match和match_phrase都会查询的字段进行分词,然后根据分词的结果去匹配,只不过后者需要匹配所有的词,而前者至少一个。比如“我喜欢她”,match只要“我”,“喜欢”,“她”,至少满足一个就好,但是match_phrase 需要三者同时满足。

    term则不对字段进行分词,也就是“我喜欢她”必须整句话满足才行。

    具体可以看 https://www.cnblogs.com/yjf512/p/4897294.html

4.6.MySQL 和 ElasticSearch(ES)比较

(1)模糊查询性能比较

    这里Mysql中共有300W+数据,ES共500W+数据

    mysql:select * from creditdefault where seg_nm like "%宝丽金%",耗时17s

    es: {"query": {"match_phrase": {"seg_nm": "宝丽金"}}} ,耗时12ms

(2)统计性能对比

    mysql:select count(distinct tel_nbr) from credit.white;耗时23.06s

            es:727ms

{
  "size": 0,
  "aggs": {
    "distinct_colors": {
      "cardinality": {
        "field": "Tel_Nbr"
      }
    }
  }
}


待续

猜你喜欢

转载自blog.csdn.net/sinat_27634939/article/details/80220321