ElasticSearch概述

ElasticSearch 是什么?

ElasticSearch 是一个基于Lucene的分布式、RESTful 风格、近实时的搜索和数据分析引擎。以下简称ES
开发语言: Java
支持客户端:Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby 等,支持REST风格调用

为什么选择ES?

市场类似类似产品:Solr
市场地位: 目前已取代Solr成为使用最多最受欢迎的搜索分析引擎
ElasticSearch 和 Solr的取舍:

  1. ElasticSearch 晚于Solr ,借鉴了Solr的成功经验 更注重扩展性,搜索实时性更高
    todo
  2. Solr在搜索静态数据时性能更高,ES在更新索引时依然可以维持稳定的搜索性能
  3. ES ,Solr搜索指数对比


    image.png

    image.png

    image.png

ES架构

作为入门,先不用过多去研究架构层次的内容,先上一张图,大概了解一下即可


image.png
1. Gateway是ES用来存储索引的文件系统,支持多种类型。
2. Gateway的上层是一个分布式的lucene框架。
3. Lucene之上是ES的模块,包括:索引模块、搜索模块、映射解析模块等
4. ES模块之上是 Discovery、Scripting和第三方插件。Discovery是ES的节点发现模块,不同机器上的ES节点要组成集群需要进行消息通信,集群内部需要选举master节点,这些工作都是由Discovery模块完成。支持多种发现机制,如 Zen 、EC2、gce、Azure。Scripting用来支持在查询语句中插入javascript、python等脚本语言,scripting模块负责解析这些脚本,使用脚本语句性能稍低。ES也支持多种第三方插件。
5. 再上层是ES的传输模块和JMX.传输模块支持多种传输协议,如 Thrift、memecached、http,默认使用http。JMX是java的管理框架,用来管理ES应用。
6. 最上层是ES提供给用户的接口,可以通过RESTful接口和ES集群进行交互。

ES常用使用场景

  1. 站内搜索: 比如各类电商,论坛,新闻,ERP网站,站内搜索功能一般都由ES或Solr支持

  2. 日志分析: 常用组合ELK,既 ES + Logstash (最新用Beats) + Kibana
    监控、统计、日志类时间序的数据存储和分析、可视化,ELK可以完美支持


    image.png
  3. 作为NoSQL Json数据库
    作为NoSQL数据库,ES比Mogo读写性能更强大,可以支持PB级数据.
    对地理位置等数据支持更好,可以方便的计算经纬度坐标的距离,坐标范围查询等功能

  4. BI系统
    BI系统也成商业智能,主要是通过数据挖掘,数据分析提供有价值的商业决策
    ES的海量数据处理能力和多样,快速的查询,统计可以提供强大的支撑

ES 常用概念

1、文档 (document)
文档是ES索引和搜索数据的最小单位。
它拥有灵活的结构。文档不依赖于预先定义的模式。并非所有的文档都需要拥有相同的字段,它们不受限于同一个模式。
不过当用于搜索时,为了提高性能通常会定义好每个字段的类型,并使用mapping定义文档结构.

2、类型 (type)
类型是文档的逻辑容器,类似于表格是行的容器。在不同的类型中,最好放入不同结构的文档。例如,可以用一个类型存放商品的数据,而另一个类型存放用户的数据。
PS: 7.X版本已彻底放弃type, 提倡每个索引存放单一类型数据,不再有type的概念了

3、索引 (index)
索引是映射类型的容器。一个Elasticsearch索引是独立的大量的文档集合。 每个索引存储在磁盘上的同组文件中,索引存储了所有映射类型的字段,还有一些设置。
当你插入一个文档时,ES默认会自动为每一个自动匹配一个类型,作为小白直接使用也是可以的, 但是正式环境使用时一般都需要根据业务需求自定义mapping去定义索引字段及字段类型才能发挥出更高的性能

4、映射(mapping)
所有文档在写入索引前都将被分析,用户可以设置一些参数,决定如何将输入文本分割为词条,哪些词条应该被过滤掉,或哪些附加处理有必要被调用(比如移除HTML标签)。这就是映射扮演的角色:存储分析链所需的所有信息。
示例:

{
  "doccenter_test" : {
    "mappings" : {
      "DcDoc" : {
        "properties" : {
          "catalogId" : {
            "type" : "keyword"
          },  
          "docConvertstatus" : {
            "type" : "keyword"
          },
          "docCreateddate" : {
            "type" : "date",
            "format" : "yyyy-MM-dd HH:mm:ss"
          },
          "docDowncount" : {
            "type" : "integer"
          },
          "docId" : {
            "type" : "keyword"
          },
          "docName" : {
            "type" : "text",
            "analyzer" : "ik_max_word"
          }
        }
      }
    }
  }
}

ES 数据类型

看了上边的mapping定义,是不是发现其中有数据类型的定义了?但是ES里具体有哪些类型呢?我们还是得像学Java一样一个个过一遍.以后定义mapping方能知其然并知其所以然

鉴于本文只做一个概述,大家了解一下即可,每个类型的具体用法和特性咱们先不做讨论

*   字符型:string
*   数字型:long:64位存储 , integer:32位存储 , short:16位存储 , byte:8位存储 , double:64位双精度存储 , float:32位单精度存储
*   日期型:date
*   布尔型: boolean
*   二进制型:binary

##### 复杂数据类型(Complex datatypes)

*   数组类型:数组类型不需要专门指定数组元素的type,例如:
    *   字符型数组: [ "one", "two" ]
    *   整型数组:[ 1, 2 ]
    *   数组型数组:[ 1, [ 2, 3 ]] 等价于[ 1, 2, 3 ]
    *   对象数组:[ { "name": "Mary", "age": 12 }, { "name": "John", "age": 10 }]
*   对象类型:* object *用于单个JSON对象;
*   嵌套类型:* nested *用于JSON数组;

##### 地理位置类型(Geo datatypes)

*   地理坐标类型:* geo_point *用于经纬度坐标;
*   地理形状类型:* geo_shape *用于类似于多边形的复杂形状;

##### 专业类型(Specialised datatypes)

*   IPv4 类型:* ip *用于IPv4 地址;
*   Completion 类型:* completion *提供自动补全建议;
*   Token count 类型:* token_count *用于统计做了标记的字段的index数目,该值会一直增加,不会因为过滤条件而减少。
*   [mapper-murmur3]:通过插件,可以通过 *murmur3 *来计算index的 hash 值;
*   附加类型(Attachment datatype):采用[mapper-attachments] 插件,可支持* attachments *索引,例如Microsoft Office 格式,Open Document 格式,ePub, HTML 等。

第一个HelloWorld(6.8版本演示)

书读百遍不如动手一遍,基础概念学完了,咱们写一个HelloWorld 找找感觉
首先你得安装好你的ES和Kibana,安装比较简单这里就不多说了

然后复习一下自从学了RESTFUL以来,从来就没有使用过的几个http请求格式
1)GET:获取请求对象的当前状态。
2)POST:改变对象的当前状态。ES中插入文档会自动生成ID
3)PUT:创建一个对象。ES中用于指定ID进行插入
4)DELETE:销毁对象。
5)HEAD:请求获取对象的基础信息。

打开Kibana,进入这个页面


image.png

自定义mapping 创建一个索引,
你会发现ES的使用就是这么简单

PUT music
{
    "mappings": {
        "_doc" : {
            "properties" : {
            
                "name" : {
                    "type": "text"
                },
                "author":{
                  "type":"keyword"
                }
            }
        }
    }
}

有了索引就可以尝试一下程序员终极技能了:增删改查

#创建索引
PUT music
{
    "mappings": {
        "musicType" : {
            "properties" : {
            
                "name" : {
                    "type": "text"
                },
                "author":{
                  "type":"text"
                }
            }
        }
    }
}
#插入文档
PUT music/musicType/10000 
{
  "name":"牧马城市",
  "author":"谁谁谁"
}
#根据id查询
GET music/musicType/10000 

#修改一下歌名
PUT music/musicType/10000
{
  "name":"牧马城市",
  "author":"毛不易"
}

#换个姿势查询所有
GET /music/musicType/_search
{
  "query":{
     "match_all": {}
  }
}
#匹配查询
GET /music/musicType/_search
{
  "query":{
    "match": {
      "name":"牧马"
    }
  }
}

#删除文档
DELETE music/musicType/10000

#换个姿势删除
POST music/musicType/_delete_by_query
{
  "query":{
    "match": {
      "name":"牧马"
    }
  }
}

#练习完毕,删除索引
DELETE music

image.png

分词器

学会了增删改查,理所当然要找个实际需求练练手了,这个时候我们就需要接触到ES的另一个概念:分词
ES之所以能够对大量文档,大段文字进行快速检索,依靠的就是对文档进行分词,然后生成倒排索引. 数据库知识比较扎实的应该对倒排索引都不陌生, 它记录了每个词的关联文档,频率等信息从而在我们需要的时候能够快速检索. 具体理论可以参考以下文章
https://www.cnblogs.com/cjsblog/p/10327673.html

而所谓分词就是按照一定规则对大段的文字进行拆分,从而得到n多个有意义的词汇。
ES默认的分词规则是针对英文的,也就是按照空格拆分.比如:我爱你祖国,会被分词为 我,爱,你,祖,国五个词. 这对中文来说跟没有分词一样,毫无用处。 所以就有了针对中文的专门的分词器:IK Analazer

IK分词器在中文分词领域是毫无争议的No1 , 甚至强到都没人知道老二是谁

我们想使用它也很简单,只需要去下载ES相同版本,放在 %ES_HOME%/config 目录下
重启ES即可

然后我们就可以在定义mapping的时候或者搜索时指定分词器

PUT music
{
    "mappings": {
        "musicType" : {
            "properties" : {
            
                "name" : {
                    "type": "text",
                    "analyzer": "ik_smart"
                },
                "author":{
                  "type":"text",
                  "analyzer": "ik_max_word"
                }
            }
        }
    }
}

大家会发现我使用了ik_smart, ik_max_word两种分词器.
这其实是IK提供的两种模式,ik_smart 是精简的分词模式,同样的文字分出的词汇比较少, ik_max_word则会尽可能多的对词进行切分

我们可以使用Kibana进行简单的测试就可以明白其中的不同

GET _analyze 
{
  "analyzer":"ik_smart",
  "text":"我是一个中国人"
}

分词结果:

{
  "tokens" : [
    {
      "token" : "我",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "CN_CHAR",
      "position" : 0
    },
    {
      "token" : "是",
      "start_offset" : 1,
      "end_offset" : 2,
      "type" : "CN_CHAR",
      "position" : 1
    },
    {
      "token" : "一个",
      "start_offset" : 2,
      "end_offset" : 4,
      "type" : "CN_WORD",
      "position" : 2
    },
    {
      "token" : "中国人",
      "start_offset" : 4,
      "end_offset" : 7,
      "type" : "CN_WORD",
      "position" : 3
    }
  ]
}


GET _analyze 
{
  "analyzer":"ik_max_word",
  "text":"我是一个中国人"
}

分词结果

{
  "tokens" : [
    {
      "token" : "我",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "CN_CHAR",
      "position" : 0
    },
    {
      "token" : "是",
      "start_offset" : 1,
      "end_offset" : 2,
      "type" : "CN_CHAR",
      "position" : 1
    },
    {
      "token" : "一个中国",
      "start_offset" : 2,
      "end_offset" : 6,
      "type" : "CN_WORD",
      "position" : 2
    },
    {
      "token" : "一个",
      "start_offset" : 2,
      "end_offset" : 4,
      "type" : "CN_WORD",
      "position" : 3
    },
    {
      "token" : "一",
      "start_offset" : 2,
      "end_offset" : 3,
      "type" : "TYPE_CNUM",
      "position" : 4
    },
    {
      "token" : "个中",
      "start_offset" : 3,
      "end_offset" : 5,
      "type" : "CN_WORD",
      "position" : 5
    },
    {
      "token" : "个",
      "start_offset" : 3,
      "end_offset" : 4,
      "type" : "COUNT",
      "position" : 6
    },
    {
      "token" : "中国人",
      "start_offset" : 4,
      "end_offset" : 7,
      "type" : "CN_WORD",
      "position" : 7
    },
    {
      "token" : "中国",
      "start_offset" : 4,
      "end_offset" : 6,
      "type" : "CN_WORD",
      "position" : 8
    },
    {
      "token" : "国人",
      "start_offset" : 5,
      "end_offset" : 7,
      "type" : "CN_WORD",
      "position" : 9
    }
  ]
}

ES 6.8 IK分词器bug

但是再好的代码也有bug, 我们在上一个项目中就遇到了一个6.8版本的bug,据说7.0已经修复. 在这里还是记录一下,毕竟我们使用的是6.8版本

这个bug就是在插入某些特定词语的时候IK分词器因为解析问题会报以下错误:

"startOffset must be non-negative, and endOffset must be >= startOffset, and offsets must not go backwards startOffset=2,endOffset=3,lastStartOffset=3 for field 'description'"

比如:2018年口腔助理考试考点:肉芽肿性唇炎的特点

解决方案也很简单:

  1. 升级版本
  2. 将报错的词语添加到自定义分词规则中
    显然第二中方案更简单一点

ES学习路线

看完上边这么多,希望大家能对ES有一个基本的轮廓,当然这只是个入门,路漫漫其修远兮,附一张ES的学习路线图,供大家参考


image.png

你可能感兴趣的:(ElasticSearch概述)