Elasticsearch是什么
Elasticsearch(简称ES)是一个基于Apache Lucene(TM)的开源搜索引擎,无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。
但是,Lucene只是一个库。想要发挥其强大的作用,你需使用Java并要将其集成到你的应用中。Lucene非常复杂,你需要深入的了解检索相关知识来理解它是如何工作的。
Elasticsearch也是使用Java编写并使用Lucene来建立索引并实现搜索功能,但是它的目的是通过简单连贯的RESTful API让全文搜索变得简单并隐藏Lucene的复杂性。
不过,Elasticsearch不仅仅是Lucene和全文搜索引擎,它还提供:
- 分布式的实时文件存储,每个字段都被索引并可被搜索
- 实时分析的分布式搜索引擎
- 可以扩展到上百台服务器,处理PB级结构化或非结构化数据
而且,所有的这些功能被集成到一台服务器,你的应用可以通过简单的RESTful API、各种语言的客户端甚至命令行与之交互。上手Elasticsearch非常简单,它提供了许多合理的缺省值,并对初学者隐藏了复杂的搜索引擎理论。它开箱即用(安装即可使用),只需很少的学习既可在生产环境中使用。Elasticsearch在Apache 2 license下许可使用,可以免费下载、使用和修改。
随着知识的积累,你可以根据不同的问题领域定制Elasticsearch的高级特性,这一切都是可配置的,并且配置非常灵活。
Elasticsearch的功能
分布式的搜索引擎和数据分析引擎
搜索:互联网搜索、电商网站站内搜索、OA系统查询。
数据分析:电商网站查询近1周哪些品类的图书销售前十;新闻网站最近三天阅读量最高的10个关键词;舆情分析。全文检索、结构化检索、数据分析
全文检索:搜索商品包含java的图书
结构化检索:搜索商品分类为Spring的图书有哪些
数据分析:分析每一个分类下有多少种图书对海量数据进行近实时的处理
分布式:ES自动可以将海量数据分散到多台服务器上去存储和检索,进行并行查询,提高检索效率。相对的Lucene是单机应用。
近实时:数据库上亿条数据查询,搜索一次耗时几个小时,是批处理(batch-processing)。而ES只需秒级即可查询海量数据,所以叫近实时,秒级。
Elasticsearch的使用场景
国外:
- 维基百科,类似百度百科,“网络七层协议”的维基百科,全文检索,高亮搜索推荐。
- Stack Overflow(国外的程序讨论论坛),相当于程序员的贴吧,遇到it问题去上面发帖,热心网友下面回答问题。
- GitHub(开源代码管理),搜索上千亿行代码。
- 电商网站,站内搜索,检索商品。
- 日志数据分析,logstash采集数据,ES进行复杂的数据分析(ELK技术,Elasticsearch+logstash+Kibana)
- 商品价格监控网站,用户设定某商品的价格阈值,当价格低于该阈值的时候,发送通知消息给用户。
- BI系统,商业智能(Business Intelligence)。大型连锁超市,分析全国网点传回的数据,分析各个商品在什么季节销售量最好、利润最高。成本管理、店面租金、员工工资、负债等信息进行分析,从而部署下一个阶段的战略目标。
国内:
- 百度搜索,第一次查询使用Elasticsearch找到相应的文档,第二次查询加入相应的广告之类的,然后返回给用户。
- OA、ERP、电商、站内搜索。
Elasticsearch的特点
- 可拓展性:大型分布式集群(数百台服务器)技术,处理PB级数据,大公司可以使用。小公司数据量小,也可以部署字啊单机。且大数据领域使用广泛。
- 技术整合:将全文检索、数据分析、分布式相关技术整合在一起,Lucene(全文检索)、商用的数据分析软件(BI软件),分布式数据库。
- 接口简单:使用restful api进行交互,跨语言。
- 功能强大:Elasticsearch作为传统数据库的一个补充,提供了传统数据库所不能提供的很多功能,如全文检索、同义词处理、相关度排名等。
Elasticsearch和Lucene的关系
- Lucene:最先进,功能最强大的搜索库。如果直接基于Lucene开发,非常复杂,api复杂。
- Elasticsearch:基于Lucene,封装了许多Lucene的底层功能,提供简单易用的restful api接口和许多语言的客户端,如Java的高级客户端(Java High Level Rest Client)和底层客户端(Java Low Level Rest Client)
Elasticsearch的核心概念
-
NRT(Near Realtime):近实时
Elasticsearch是一个接近实时的搜索平台,这意味着,从索引一个文档直到这个文档能够被搜索到有一个轻微的延迟(通常是1秒)。主要体现在两个方面: - 写入数据时,过1秒才会被搜索到,因为内部在分词、录入索引。
- ES搜索时,搜索和分析数据需要秒级出结果。
Cluster:集群
一个集群包含一个或多个启动着es实例的机器群,通常一台机器起一个es实例,它们共同持有你整个的数据,并一起提供索引和搜索功能。同一网络下,集群名一样的多个es实例自动组成集群,自动均衡分片等行为,一个集群由一个唯一的名字标识,默认集群名为"elasticsearch"。这个名字是重要的,因为一个节点只能通过指定某个集群的名字,来加入这个集群。在产品环境中显式地设定这个名字是一个好习惯,但是使用默认值来进行测试/开发也是不错的。节点:node
每个es实例称为一个节点,节点名自动分配,也可以手动配置。
一个节点是你集群中的一个服务器,作为集群的一部分,它存储你的数据,参与集群的索引和搜索功能。和集群类似,一个节点也是由一个名字来标识的,默认情况下,这个名字是一个随机的漫威漫画角色的名字,这个名字会在启动的时候赋予节点。这个名字对于管理工作来说挺重要的,因为在这个管理过程中,你会去确定网络中的哪些服务器对应于Elasticsearch集群中的哪些节点。
一个节点可以通过配置集群名称的方式来加入一个指定的集群。默认情况下,每个节点都会被安排加入到一个叫做“elasticsearch”的集群中,这意味着,如果你在你的网络中启动了若干个节点,并假定它们能够相互发现彼此,它们将会自动地形成并加入到一个叫做“elasticsearch”的集群中。
-
Index:索引
一个索引就是包含一堆有相似结构的文档数据。
索引创建规则:- 仅限小写字母
- 不能包含\、/、*、?、"、<、>、|、#以及空格符等 特殊符号。
- 从7.0版本开始不在包含冒号。
- 不能以-、_或+开头。
- 不能超过255个字节(注意是字节,因此多字节字符将计入255个限制)
当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。索引类似于关系型数据库中Database的概念。在一个集群中,如果你想,可以定义任意多的索引。
Field:字段
就像数据库中的列(Columns),定义每个document应该有的字段。Type:类型
每个索引里都有一个或多个type,type是index中的一个逻辑数据分类,一个type下的document,都有相同的field。
在一个索引中,你可以定义一种或多种类型。一个类型是你的索引的一个逻辑上的分类/分区,其语义完全由你来定。通常,会为具有一组共同字段的文档定义一个类型。比如说,我们假设你运营一个博客平台并且将你所有的数据存储到一个索引中。在这个索引中,你可以为用户数据定义一个类型,为博客数据定义另一个类型,当然,也可以为评论数据定义另一个类型。类型类似于关系型数据库中Table的概念。
-
Document:文档
一个文档是一个可被索引的基础信息单元。一个Document就像数据库中的一行记录,通常以json格式显示,多个Document存储于一个索引(Index)中。文档以JSON(Javascript Object Notation)格式来表示,而JSON是一个到处存在的互联网数据交互格式。
在一个index/type里面,只要你想,你可以存储任意多的文档。注意,尽管一个文档,物理上存在于一个索引之中,文档必须被索引/赋予一个索引的type。文档类似于关系型数据库中Record的概念。实际上一个文档除了用户定义的数据外,还包括_index、_type和_id字段。
Shard:分片
index数据过大时,将index里面的数据,分为多个shard,分布式的存储在各个服务器上面,可以支持海量数据和高并发,提升性能和吞吐量,充分利用多台机器的CPU。replica:副本
在分布式环境下,任何一台机器都会随时宕机,如果宕机,index的一个分片没有导致此index不能搜索。所以为了保证数据安全,我们会将每个index的分片进行备份,存储在另外的机器上,保证少数机器宕机,ES集群仍然可以提供搜索服务。
能正常提供查询和插入的分片我们叫做主分片(primary shard),其余的我们就管它们叫做备份的分片(replica shard)。
ES6默认新建索引时,5分片,1副本,也就是一主一备,共10个分片。所以,ES集群最小规模为2台。ES7,默认1分片,1副本,一共2分片。
shard & replica说明:
一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢。
为了解决这个问题,Elasticsearch提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。
分片之所以重要,主要有两方面的原因:
允许你水平分割/扩展你的内容容量,允许你在分片(潜在地,位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量,至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由Elasticsearch管理的,对于作为用户的你来说,这些都是透明的。
在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了。这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。复制之所以重要,主要有两方面的原因:
在分片/节点失败的情况下,提供了高可用性。因为这个原因,注意到复制分片从不与原/主要(original/primary)分片置于同一节点上是非常重要的。
扩展你的搜索量/吞吐量,因为搜索可以在所有的复制上并行运行
总之,每个索引可以被分成多个分片。一个索引也可以被复制0次(意思是没有复制)或多次。一旦复制了,每个索引就有了主分片(作为复制源的原来的分片)和复制分片(主分片的拷贝)之别。分片和复制的数量可以在索引创建的时候指定。在索引创建之后,你可以在任何时候动态地改变复制数量,但是不能改变分片的数量。
默认情况下,Elasticsearch中的每个索引被分片5个主分片和1个复制,这意味着,如果你的集群中至少有两个节点,你的索引将会有5个主分片和另外5个复制分片(1个完全拷贝),这样的话每个索引总共就有10个分片。一个索引的多个分片可以存放在集群中的一台主机上,也可以存放在多台主机上,这取决于你的集群机器数量。主分片和复制分片的具体位置是由ES内在的策略所决定的。
数据库核心概念 VS Elasticsearch核心概念
关系型数据库(MySQL) | 非关型数据库(Elasticsearch) |
---|---|
数据库Database | 索引Index |
表Table | 索引Index(原为Type) |
数据行Row | 文档Document |
数据列Column | 字段Field |
约束Schema | 映射Mapping |
关于索引
1.1 关于索引的一些基础知识
在创建标准化索引的时候,我们传入的请求体如下:
{
"settings":{
"number_of_shards":5,
"number_of_replicas":1
},
"mappings":{
"novel":{
"properties":{
"id":{
"type":"integer"
},
"book_name":{
"type":"text"
},
"author":{
"type":"keyword"
},
"brief_introduction":{
"type":"text"
},
"publish_date":{
"type":"date",
"format":"yyyy-MM-dd HH:mm:ss || yyyy-MM-dd"
},
"word_count":{
"type":"integer"
}
}
}
}
}
首先,ElasticSearch的对象模型如下:
- 索引(Index):相当于数据库,用于定义文档类型的存储;在同一个索引中,同一个字段只能定义一个数据类型;
- 文档类型(Type):相当于关系表,用于描述文档中的各个字段的定义;不同的文档类型,能够存储不同的字段,服务于不同的查询请求;
-
文档(Document):相当于关系表的数据行,存储数据的载体,包含一个或多个存有数据的字段;
- 字段(Field):文档的一个Key/Value对;
- 词(Term):表示文本中的一个单词;
- 标记(Token):表示在字段中出现的词,由该词的文本、偏移量(开始和结束)以及类型组成;
所以,上面的请求体我们就可以这样标记:
详细的解释下:
type:目前在6.0的时候,有keyword和text,区别为:
- keyword:数据类型用来建立电子邮箱地址、姓名、邮政编码和标签等数据类型,不需要进行分词。可以被用来检索过滤、排序和聚合。keyword 类型字段只能用本身来进行检索。
- text:Text 数据类型被用来索引长文本,这些文本会被分析,在建立索引前会将这些文本进行分词,转化为词的组合,建立索引。比如你配置了IK分词器,那么就会进行分词,搜索的时候会搜索分词来匹配这个text文档。但是:text 数据类型不能用来排序和聚合
1.2 关于索引的自动创建禁止与否
在上篇博客中,我们提到,当我们插入数据的时候,如果有超出我们结构化的数据的时候,索引会自动更新数据,但是很多时候会出现,不是同一个人操作的时候,插入的数据各式各样的,最后导致索引无法使用!如何解决?
dynamic属性有三个值:
- true:默认,可以自动创建索引,插入数据字段不符合的话就创建新的索引。
- false:不自动创建索引,当插入数据不符合默认属性的时候,忽略新插入的不符合的字段的值。
- strict:精确的,不允许插入不符合默认属性的值,如果不符合,直接报错。
我们可以在创建索引的时候,指定索引是绝对的,精确的,就可以避免因为写错而更新了新的字段,如下图:当然我们也可以设置当插入字段和我们预先定义的映射不符的话,忽略这些新插入的字段,但是这样的话后期查找问题可能会比较麻烦。
这样的话,当你插入不符合标准化索引的时候,就会提示错误而导致无法插入,当然这样也有麻烦的地方,如果插入数据出错,可能会导致数据丢失,所以如果在项目中你需要这样做的话,最好可以将失败的数据写入日志文件或者直接写入数据库,这样就可以避免数据的丢失了,也可以重新拿到失败的数据进行重新索引。
1.3 关于文档类型的属性
文档属性定义了文档类型的共用属性,适用于文档的所有字段。当然也可以指定字段属性,只适用于某个特定的字段。
- dynamic_date_formats属性:该属性定义可以识别的日期格式列表;如果文档中有多个字段都是时间格式,可以通用的进行设置。
- dynamic属性:默认为true,允许动态地向文档类型中加入新的字段。可选值为:true,false,strict
1.4 关于文档字段的属性值
1.4.1 字段的数据类型
字段的数据类型由字段的属性type指定,ElasticSearch支持的基础数据类型主要有:
- 字符串类型:keyword和text。(在5.0之后更改,原来为string)。详细的介绍见1.1。
- 数值类型:字节(byte)、2字节(short)、4字节(integer)、8字节(long)、float、double;
- 布尔类型:boolean,值是true或false;
- 时间/日期类型:date,用于存储日期和时间;
- 二进制类型:binary;
- IP地址类型:ip,以字符串形式存储IPv4地址;
- 特殊数据类型:token_count,用于存储索引的字数信息
1.4.2 字段的公共属性:
-
index:该属性控制字段是否编入索引被搜索,该属性共有三个有效值:analyzed、no和not_analyzed:store:指定是否将字段的原始值写入索引,默认值是no,字段值被分析,能够被搜索,但是,字段值不会存储,这意味着,该字段能够被查询,但是不会存储字段的原始值。
- analyzed:(默认属性)表示该字段被分析,编入索引,产生的token能被搜索到;
- not_analyzed:表示该字段不会被分析,使用原始值编入索引,在索引中作为单个词;
- no:不编入索引,无法搜索该字段;
- 其中analyzed是分析,分解的意思,默认值是analyzed,表示将该字段编入索引,以供搜索。
- **boost:字段级别的助推,默认值是1,定义了字段在文档中的重要性/权重;
- **include_in_all:该属性指定当前字段是否包括在_all字段中,默认值是ture,所有的字段都会包含_all字段中;如果index=no,那么属性include_in_all无效,这意味着当前字段无法包含在_all字段中。
- **copy_to:该属性指定一个字段名称,ElasticSearch引擎将当前字段的值复制到该属性指定的字段中;
- **doc_values:文档值是存储在硬盘上的索引时(indexing time)数据结构,对于not_analyzed字段,默认值是true,analyzed string字段不支持文档值;
- **fielddata:字段数据是存储在内存中的查询时(querying time)数据结构,只支持analyzed string字段;
- **null_value:该属性指定一个值,当字段的值为NULL时,该字段使用null_value代替NULL值;在ElasticSearch中,NULL 值不能被索引和搜索,当一个字段设置为NULL值,ElasticSearch引擎认为该字段没有任何值,使用该属性为NULL字段设置一个指定的值,使该字段能够被索引和搜索。
1.4.3 字符串类型常用的其他属性
- analyzer:该属性定义用于建立索引和搜索的分析器名称,默认值是全局定义的分析器名称,该属性可以引用在配置结点(settings)中自定义的分析器;
- search_analyzer:该属性定义的分析器,用于处理发送到特定字段的查询字符串;
- ignore_above:该属性指定一个整数值,当字符串字段(analyzed string field)的字节数量大于该数值之后,超过长度的部分字符数据将不能被analyzer处理,不能被编入索引;对于 not analyzed string字段,超过长度的部分字符将被忽略,不会被编入索引。默认值是0,禁用该属性;
- position_increment_gap:该属性指定在相同词的位置上增加的gap,默认值是100;
-
index_options:索引选项控制添加到倒排索引(Inverted Index)的信息,这些信息用于搜索(Search)和高亮显示:
- docs:只索引文档编号(Doc Number)
- freqs:索引文档编号和词频率(term frequency)
- positions:索引文档编号,词频率和词位置(序号)
- offsets:索引文档编号,词频率,词偏移量(开始和结束位置)和词位置(序号)
- 默认情况下,被分析的字符串(analyzed string)字段使用positions,其他字段使用docs;
分析器(analyzer)把analyzed string 字段的值,转换成标记流(Token stream),例如,字符串"The quick Brown Foxes",可能被分解成的标记(Token)是:quick,brown,fox。这些词(term)是该字段的索引值,这使用对索引文本的查找更有效率。字段的属性 analyzer 用于指定在index-time和search-time时,ElasticSearch引擎分解字段值的分析器名称。
2. 关于请求方法
在使用ElasticSearch的时候,我们会牵扯到很多的请求方法,比如GET,POST,PUT,DELETE等等,这些方法使用的都是Restful的调用风格,我们来简单介绍下这些方法
-
GET 请求:获取服务器中的对象
- 相当于SQL的Select命令
- GET /book 获取所有的book信息
-
POST 请求:在服务器上更新对象
- 相当于SQL的update命令
- POST /book/1 更新id为1的book的信息
-
PUT 请求:在服务器上创建对象
- 相当于SQL的create命令
- PUT /book/id 创建一个id为xx的书
-
DELETE 请求:删除服务器中的对象HEAD 请求:仅仅用于获取对象的基础信息
- 相当于sql中的delete命令
- DELETE /book/1 删除id为1的书
参考:
https://www.cnblogs.com/sunsky303/p/9438737.html
https://www.jianshu.com/p/625d553188b4