Elasticsearch初探

Elasticsearch是什么

Elasticsearch是一个基于Apache Lucene(TM)的一个分布式的开源搜索和分析引擎

Elasticsearch实现的功能

  • 分布式的搜索引擎

    Elasticsearch自动将海量数据分散到多台服务器进行存储和检索

  • 全文检索

    Elasticsearch提供了模糊搜索等自动度很高的查询方式,并进行相关排名,高亮等功能

  • 数据分析

    可以做分组聚合

  • 对海量数据进行实时处理

    因为Elasticsearch是分布式架构,可以采用大量的服务器进行存储和检索数据,可以实现秒级数据搜索和分析

使用场景

  • 搜索类场景
  • 日志分析 (经典的ELK组合完成日志收集、存储、分析、查询功能)
  • 数据预警、分析平台(分析电商平台评论数、访问量、关注度等等)
  • 商业BI系统 (分析上一季度消费金额、年龄段、访问时间段的人数分布等等)

全文搜索方案对比

  • solr

    Solr是一个有HTTP接口的基于Lucene的查询服务器,封装了很多Lucene细节,自己的应用可以直接利用诸如 .../solr?q=abc 这样的HTTP GET/POST请求去查询,维护修改索引。

  • Elasticsearch

    Elasticsearch也是一个建立在全文搜索引擎 Apache Lucene基础上的搜索引擎。采用的策略是分布式实时文件存储,并将每一个字段都编入索引,使其可以被搜索。

两者者之间的一个联系:solr和Elasticsearch都是基于Lucene实现的

区别:

  • Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能;
  • Solr 支持更多格式的数据,而 Elasticsearch 仅支持json文件格式;
  • Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高级功能多有第三方插件提供;
  • Solr 在传统的搜索应用中表现好于 Elasticsearch,但在处理实时搜索应用时效率明显低于 Elasticsearch

核心概念

索引(index)

ElasticSearch将它的数据存储在一个或多个索引(index)中。用SQL领域的术语来类比,索引就像数据库,可以向索引写入文档或者从索引中读取文档,并通过ElasticSearch内部使用Lucene将数据写入索引或从索引中检索数据。

类型(type)

类型是模拟mysql中的table概念,一个索引库下可以有不同类型的索引,比如商品索引,订单索引,其数据格式不同。不过这会导致索引库混乱,因此未来版本中会移除这个概念

ES中每个大版本的type类型有很大区别

ES 5.x 中index可以又多种type

ES 6.x 中一个index只能有一个type

ES 7.x以后要逐渐移除这个概念

文档(document)

文档(document)是ElasticSearch中的主要实体。对所有使用ElasticSearch的案例来说,他们最终都可以归结为对文档的搜索。文档由字段构成。

在一个index/type里面,你可以存储任意多的文档。注意,尽管一个文档,物理上存在于一个索引之中,文档必须被索引/赋予一个索引的type。

字段Field

相当于是数据表的字段,对文档数据根据不同属性进行的分类标识

映射 mapping

mapping就相当于我们关系型数据库中的表结构,是处理数据的方式和规则方面做一些限制,如某个字段的数据类型、默认值、分析器、是否被索引等等,这些都是映射里面可以设置的,其它就是处理es里面数据的一些使用规则设置也叫做映射,按着最优规则处理数据对性能提高很大,因此才需要建立映射,并且需要思考如何建立映射才能对性能更好。

集群 cluster

一个集群就是由一个或多个节点组织在一起,它们共同持有整个的数据,并一起提供索引和搜索功能。一个集群由一个唯一的名字标识,这个名字默认就是“elasticsearch”。这个名字是重要的,因为一个节点只能通过指定某个集群的名字,来加入这个集群

可以通过get请求查看集群状态:

http://es地址:9200/_cat/health?v

返回数据:

epoch      timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1645155625 11:40:25  sxjyes  green           3         3    252 126    0    0        0             0                  -                100.0%

参数说明:

cluster:集群名称
status:集群状态 green代表健康;yellow代表分配了所有主分片,但至少缺少一个副本,此时集群数据仍旧完整;red代表部分主分片不可用,可能已经丢失数据。
node.total:代表在线的节点总数量
node.data:代表在线的数据节点的数量
shards, active_shards: 存活的分片数量
pri,active_primary_shards: 存活的主分片数量 正常情况下 shards的数量是pri的两倍。
relo, relocating_shards :迁移中的分片数量,正常情况为 0
init, initializing_shards: 初始化中的分片数量 正常情况为 0
unassign, unassigned_shards: 未分配的分片 正常情况为 0
pending_tasks:准备中的任务,任务指迁移分片等 正常情况为 0
max_task_wait_time:任务最长等待时间
active_shards_percent:正常分片百分比 正常情况为 100%

节点 node

一个节点是集群中的一个服务器,作为集群的一部分,它存储数据,参与集群的索引和搜索功能。和集群类似,一个节点也是由一个名字来标识的,默认情况下,这个名字是一个随机的漫威漫画角色的名字,这个名字会在启动的时候赋予节点。这个名字对于管理工作来说挺重要的,因为在这个管理过程中,你会去确定网络中的哪些服务器对应于Elasticsearch集群中的哪些节点。

一个节点可以通过配置集群名称的方式来加入一个指定的集群。默认情况下,每个节点都会被安排加入到一个叫做“elasticsearch”的集群中,这意味着,如果你在你的网络中启动了若干个节点,并假定它们能够相互发现彼此,它们将会自动地形成并加入到一个叫做“elasticsearch”的集群中。

在一个集群里,只要你想,可以拥有任意多个节点。而且,如果当前你的网络中没有运行任何Elasticsearch节点,这时启动一个节点,会默认创建并加入一个叫做“elasticsearch”的集群。

分片和复制 shards&replicas

一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢。为了解决这个问题,Elasticsearch提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。分片很重要,主要有两方面的原因:
1)允许你水平分割/扩展你的内容容量。
2)允许你在分片(潜在地,位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量。

至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由Elasticsearch管理的,对于作为用户的你来说,这些都是透明的。

在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了,这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。

复制之所以重要,有两个主要原因: 在分片/节点失败的情况下,提供了高可用性。因为这个原因,注意到复制分片从不与原/主要(original/primary)分片置于同一节点上是非常重要的。扩展你的搜索量/吞吐量,因为搜索可以在所有的复制上并行运行。总之,每个索引可以被分成多个分片。一个索引也可以被复制0次(意思是没有复制)或多次。一旦复制了,每个索引就有了主分片(作为复制源的原来的分片)和复制分片(主分片的拷贝)之别。分片和复制的数量可以在索引创建的时候指定。在索引创建之后,你可以在任何时候动态地改变复制的数量,但是你事后不能改变分片的数量。

默认情况下,Elasticsearch中的每个索引被分片5个主分片和1个复制,这意味着,如果你的集群中至少有两个节点,你的索引将会有5个主分片和另外5个复制分片(1个完全拷贝),这样的话每个索引总共就有10个分片。

Elasticsearch概念和关系型数据库的对比

关系型数据库(如mysql) Elasticsearch
数据库 索引index
表(table) 索引index类型(原为type)
数据行row 文档(document)
数据列(column) 字段Field
约束 schema 映射 mapping

字段类型

字段类型分为基本类型和复合类型‘

基本类型

字符串类型
  • string

    string类型在ElasticSearch 旧版本中使用较多,从ElasticSearch 5.x开始不再支持string,由text和keyword类型替代。

  • text

    当一个字段是要被全文搜索的,比如Email内容、产品描述,应该使用text类型。设置text类型以后,字段内容会被分析,在生成倒排索引以前,字符串会被分析器分成一个一个词项。text类型的字段不用于排序,很少用于聚合。

    text会分词,然后进行索引,支持模糊、精确查询,不支持聚合

  • keyword

    这种类型适用于结构化的字段,例如标签、email 地址、手机号码等等,这种类型的字段可以用作过滤、排序、聚合等。这种字符串也称之为 not-analyzed 字段。

    keyword不进行分词,直接索引,支持模糊、精确查询,支持聚合

数字类型

数字类型有long、integer、short、byte、double、float、half_float、scaled_float。

  • 在满足需求的情况下,优先使用范围小的字段。字段长度越短,索引和搜索的效率越高。比如,某个字段的取值最大值不会超过100,那么选择byte类型即可。迄今为止吉尼斯记录的人类的年龄的最大值为134岁,对于年龄字段,short足矣字段的长度越短,索引和搜索的效率越高。
  • 浮点数,优先考虑使用 scaled_float。
日期类型

由于 JSON 中没有日期类型,所以 es 中的日期类型形式就比较多样:2020-11-11 或者 2020-11-11 11:11:11,一个从 1970.1.1 零点到现在的一个秒数或者毫秒数。es 内部将时间转为 UTC,然后将时间按照 millseconds-since-the-epoch 的长整型来存储。

boolean类型

逻辑类型(布尔类型)可以接受true/false/”true”/”false”值

二进制类型(binary)

二进制字段是指用base64来表示索引中存储的二进制数据,可用来存储二进制形式的数据,例如图像。默认情况下,该类型的字段只存储不索引。二进制类型只支持index_name属性。

范围类型(range)

数据范围类型,一个字段表示一个范围,具体包含以下类型:

  • integer_range
  • float_range
  • double_range
  • date_range
  • ip_range

所谓的范围类型,就是一个值自身就表明一个范围,如:

PUT range_index
 {
   "mappings": {
     "_doc": {
       "properties": {
        "expected_attendees": {
           "type": "integer_range"
        }
      }
   }
  }
}

复合类型

数组类型(array)

es 中没有专门的数组类型。默认情况下,任何字段都可以有一个或者多个值。需要注意的是,数组中的元素必须是同一种类型。添加数组是,数组中的第一个元素决定了整个数组的类型。

对象类型(object)

由于 JSON 本身具有层级关系,所以文档包含内部对象。内部对象中,还可以再包含内部对象。

IK分词器

Elasticsearch自带的标准分词器是针对英文的,所以我们在日常开发中都是使用ik分词器,它是一个针对中文的分词器。

从2016年12月推出1.0版本开始,IKAnalyzer已经推出了三个大版本,最初他是以开源项目Lucene为应用主题的,结合词典分词和文法分析算法的中文分词组件,新版的IKAnalyzer3.0则发展为面向java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现

IKAnalyzer3.0版本特性如下:

  • 采用了特有的“正向迭代最细粒度切分算法“,具有50万字/秒的高速处理能力。
  • 采用了多子处理器分析模式,支持:英文字母(IP地址、Email、URL)、数字(日期,常用中文数量词,罗马数字,科学计数法),中文词汇(姓名、地名处理)等分词处理。
  • 优化的词典存储,更小的内存占用。支持用户词典扩展定义
  • 针对Lucene全文检索优化的查询分析器IKQueryParser;采用歧义分析算法优化查询关键字的搜索排列组合,能极大的提高Lucene检索的命中率。

IK分词器有两种分词模式:ik_max_word和ik_smart模式。

ik_max_word

会将文本做最细粒度的拆分,比如会将“中华人民共和国人民大会堂”拆分为“中华人民共和国、中华人民、中华、华人、人民共和国、人民、共和国、大会堂、大会、会堂等词语。

ik_smart

会做最粗粒度的拆分,比如会将“中华人民共和国人民大会堂”拆分为中华人民共和国、人民大会堂。

IK分词器扩展词典

停用词扩展
  • 1) 我们找到IK的配置文件,位于ik/config/IKAnalyzer.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
        <comment>IK Analyzer 扩展配置</comment>
        <!--用户可以在这里配置自己的扩展字典 -->
        <entry key="ext_dict">ext_dic.dic</entry>
         <!--用户可以在这里配置自己的扩展停止词字典-->
        <entry key="ext_stopwords"></entry>
        <!--用户可以在这里配置远程扩展字典 -->
        <!-- <entry key="remote_ext_dict">words_location</entry> -->
        <!--用户可以在这里配置远程扩展停止词字典-->
        <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
  • 2)在配置文件中增加配置的停用词文件的节点:
<entry key="ext_stopwords">my_ext_stopword.dic</entry>
  • 3)在类目前下创建扩展停用词文件my_ext_stopword.dic

  • 4) 在文件my_ext_stopword.dic中添加词,一行一个

扩展字典
  • 1) 我们找到IK的配置文件,位于ik/config/IKAnalyzer.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
        <comment>IK Analyzer 扩展配置</comment>
        <!--用户可以在这里配置自己的扩展字典 -->
        <entry key="ext_dict">ext_dic.dic</entry>
         <!--用户可以在这里配置自己的扩展停止词字典-->
        <entry key="ext_stopwords"></entry>
        <!--用户可以在这里配置远程扩展字典 -->
        <!-- <entry key="remote_ext_dict">words_location</entry> -->
        <!--用户可以在这里配置远程扩展停止词字典-->
        <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
  • 2)在配置文件中增加配置的停用词文件的节点:
<entry key="ext_dict">my_ext_dict.dic</entry>
  • 3)在类目前下创建扩展停用词文件my_ext_dict.dic

  • 4) 在文件my_ext_dict.dic中添加词,一行一个

同义词词典

Elasticsearch 自带一个名为 synonym 的同义词 filter。为了能让 IK 和 synonym 同时工作,我们需要定义新的 analyzer,用 IK 做 tokenizer,synonym 做 filter。

  • 打开 /config/elasticsearch.yml 文件,加入以下配置:
index:  
  analysis:  
    analyzer:  
      ik_syno:  
          type: custom  
          tokenizer: ik_max_word  
          filter: [my_synonym_filter]  
      ik_syno_smart:  
          type: custom  
          tokenizer: ik_smart  
          filter: [my_synonym_filter]  
    filter:  
      my_synonym_filter:  
          type: synonym  
          synonyms_path: analysis/synonym.txt  

以上配置定义了 ik_syno 和 ik_syno_smart 这两个新的 analyzer,分别对应 IK 的 ik_max_word 和 ik_smart 两种分词策略

  • 创建/config/analysis/synonym.txt 文件,输入一些同义词并存为 utf-8 格式。例如

  • 重启es即可

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容