ElasticSearch 是什么?
ElasticSearch 是一个基于Lucene的分布式、RESTful 风格、近实时的搜索和数据分析引擎。以下简称ES
开发语言: Java
支持客户端:Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby 等,支持REST风格调用
为什么选择ES?
市场类似类似产品:Solr
市场地位: 目前已取代Solr成为使用最多最受欢迎的搜索分析引擎
ElasticSearch 和 Solr的取舍:
- ElasticSearch 晚于Solr ,借鉴了Solr的成功经验 更注重扩展性,搜索实时性更高
todo - Solr在搜索静态数据时性能更高,ES在更新索引时依然可以维持稳定的搜索性能
-
ES ,Solr搜索指数对比
ES架构
作为入门,先不用过多去研究架构层次的内容,先上一张图,大概了解一下即可
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常用使用场景
站内搜索: 比如各类电商,论坛,新闻,ERP网站,站内搜索功能一般都由ES或Solr支持
-
日志分析: 常用组合ELK,既 ES + Logstash (最新用Beats) + Kibana
监控、统计、日志类时间序的数据存储和分析、可视化,ELK可以完美支持
作为NoSQL Json数据库
作为NoSQL数据库,ES比Mogo读写性能更强大,可以支持PB级数据.
对地理位置等数据支持更好,可以方便的计算经纬度坐标的距离,坐标范围查询等功能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,进入这个页面
自定义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
分词器
学会了增删改查,理所当然要找个实际需求练练手了,这个时候我们就需要接触到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年口腔助理考试考点:肉芽肿性唇炎的特点
解决方案也很简单:
- 升级版本
- 将报错的词语添加到自定义分词规则中
显然第二中方案更简单一点
ES学习路线
看完上边这么多,希望大家能对ES有一个基本的轮廓,当然这只是个入门,路漫漫其修远兮,附一张ES的学习路线图,供大家参考