ElasticSearch详解(篇一)
目录
前言
这篇博客主要讲解ElasticSearch,由于篇幅过长,这个博客也是分为两篇,篇一主要讲解ElasticSearch的基础概念和原理,安装部署,以及索引库和文档基本操作,希望看完这篇博客能让新人对Elasticsearch有一个直观的认识。
一,Elasticsearch概述与核心概念
什么是Elasticsearch
- Elasticsearch是一款开源的分布式搜索引擎,基于Java开发,采用Lucene作为核心搜索库。其发展历程可追溯至2004年,当时Shay Banon基于Lucene开发了Compass,随后在2010年重写并命名为Elasticsearch
技术优势与生态系统
Elasticsearch具备显著的技术优势
- 分布式架构:支持水平扩展,能够处理海量数据
- RESTful接口:提供标准的HTTP API,可被任何编程语言调用
- 高性能搜索:基于倒排索引技术,查询速度极快
Elasticsearch与Kibana、Logstash、Beats共同构成ELK技术栈,被广泛应用于日志数据分析、实时监控等领域。

而elasticsearch是elastic stack的核心,负责存储、搜索、分析数据。

核心概念解析
文档和字段
- elasticsearch是面向文档(Document)存储的,可以是数据库中的一条商品数据,一个订单信息。文档数据会被序列化为json格式后存储在elasticsearch中

- 因此,传统数据库中的一行数据就是ES中的一个JSON文档;而数据库中每行数据都包含很多列,这些列就转换为JSON文档中的字段(Field)
索引和映射
索引
- Elasticsearch中的索引不是传统数据库中的索引,而是“表”,比如商品文档、用户的文档、订单文档等,将同类型的文档集中在一起管理,成为索引。例如:

映射(mapping)
-
传统数据库中的表会有约束信息,用来定义表的结构、字段名称、类型、主键约束等等。同样的,在elasticsearch,在创建索引(表)时,也必须有这样的约束信息,在elasticsearch中,这样的约束信息被称为mapping(映射),用于定义索引中的document的字段名称、类型等结构和约束。
-
常见的Mapping属性包括:

-
需要注意的是,mapping中的index(索引),指的是为这个字段创建常规索引,便于根据该字段快速查询数据,类比于mysql中的聚集索引和非聚集索引,elasticsearch中的索引概念比较混乱,这里需要理解。
-
例如下面的json文档:
{"age": 21,"weight": 52.1,"isMarried": false,"info": "黑马程序员Java讲师","email": "zy@itcast.cn","score": [99.1, 99.5, 98.9],"name": {"firstName": "云","lastName": "赵"} }对应的每个字段映射(Mapping):

mysql与elasticsearch
-
学习Elasticsearch对照MySQL,pg关系型数据库会理解的更深刻,本质上可以这样理解,Elasticsearch也是一个数据库,基于倒排索引检索存储的数据,除此之外,还提供数据分析的功能,仅此而已。Elasticsearch需要掌握以下基本概念:
MySQL/PG概念 Elasticsearch对应 说明 Table Index 索引,即文档的集合,类似数据库的表 Row Document 文档,一条条的数据,采用JSON格式 Column Field 字段,JSON文档中的属性,类似数据库列 Schema Mapping 映射,索引中 文档的字段约束信息, 字段什么名字,什么类型,需不需要倒排索引等等 SQL DSL Elasticsearch提供的JSON风格查询语句

二,倒排索引原理与分词器
倒排索引工作机制
-
讲倒排索引之前,先回顾一下mysql、pg等传统数据库的正向索引,什么是正向索引,简单来说,就是根据关键词检索数据时,依次将数据库表中的记录去匹配查询关键词条件,重点是看记录中包不包含关键词,将包含关键词的记录一条一条检索出来,下面这个图是一个比较经典的正向索引查新数据的过程。

-
与传统数据库的正向索引不同,Elasticsearch采用倒排索引技术,倒排索引有两个非常重要的概念:
概念 说明 文档(Document) Elasticsearch存储的数据,用来搜索的数据,其中的每一条数据就是一个文档。例如一个网页、一个商品信息,类比传统数据库中的Row 词条(Term) 对文档数据或用户搜索数据,利用某种算法分词,得到的具备含义的词语就是词条。例如:我是中国人,就可以分为:我、是、中国人、中国、国人这样的几个词条 -
倒排索引的核心思想是对文档内容进行分词,对词条创建索引,并记录词条所在文档的ID。查询时先根据词条查询到文档ID,再获取完整文档。注意,这里所说的索引不是指mysql、pg等传统数据库地索引,索引在Elasticsearch中,是类似于传统数据库的表的概念,可以这样简单理解,正向索引就是存放文档(document)的表,倒排索引是正向索引中拆分出来的词语表。

-
倒排索引的搜索流程如下(以搜索"华为手机"为例),如图所示。Elasticsearch先将用户输入的查询条件进行分词,然后在词语倒排索引中进行查找,由于词条有索引(注意理解,这个索引指的是系统为倒排索引内部的“词条字典”(Term Dictionary)这个组成部分本身又建立了一层高效的索引结构(通常是 Term Index)),所以查询效率也高。
-
虽然要先查询倒排索引,再查询倒排索引,但是无论是词条、还是文档id都建立了索引,查询速度非常快!无需全表扫描

正向和倒排的优缺点
| 索引 | 优点 | 缺点 |
|---|---|---|
| 正向索引 | 可以给多个字段创建索引, - 根据索引字段搜索、排序速度非常快 | 根据非索引字段,或者索引字段中的部分词条查找时,只能全表扫描 |
| 倒排索引 | - 根据词条搜索、模糊搜索时,速度非常快 | - 只能给词条创建索引,而不是字段, - 无法根据字段做排序 |
IK中文分词器
- 由于中文分词的复杂性,需要专门的中文分词器。IK分词器采用正向迭代最细粒度切分算法,提供两种分词模式
- ik_smart:智能切分,粗粒度
- ik_max_word:最细切分,细粒度
-
我们在调用Elasticsearch Restfull接口时,可以指定分词器的工作模式。
POST /_analyze {"analyzer": "ik_max_word","text": "传智播客开设大学,真的泰裤辣!" } -
如果我们想要扩展IK分词器分词的基本词汇,IK分词器提供了扩展词汇的功能,我们只需要创建一个自定义的新增词语文件,然后在IK分词器配置文件中关联一下即可。

-
在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</entry> </properties>
三,索引库操作
-
创建索引库, 请求方式:PUT,请求参数:mapping映射
PUT /索引库名称 {"mappings": {"properties": {"字段名":{"type": "text","analyzer": "ik_smart"},"字段名2":{"type": "keyword","index": "false"},"字段名3":{"properties": {"子字段": {"type": "keyword"}}},// ...略}} }
- 查询索引库:GET /索引库名
- 删除索引库:DELETE /索引库名
- 修改索引库
-
倒排索引结构虽然不复杂,但是一旦数据结构改变(比如改变了分词器),就需要重新创建倒排索引,这简直是灾难。因此索引库一旦创建,无法修改mapping。
-
虽然无法修改mapping中已有的字段,但是却允许添加新的字段到mapping中,因为不会对倒排索引产生影响。因此修改索引库能做的就是向索引库中添加新字段,或者更新索引库的基础属性。
PUT /索引库名/_mapping {"properties": {"新字段名":{"type": "integer"}} }
-
四,文档操作
新增文档
-
语法如下:
POST /索引库名/_doc/文档id {"字段1": "值1","字段2": "值2","字段3": {"子属性1": "值3","子属性2": "值4"}, }示例:

查询文档
-
语法如下:
GET /{索引库名称}/_doc/{id}示例:

删除文档
删除使用DELETE请求,同样,需要根据id进行删除:
DELETE /{索引库名}/_doc/id值
修改文档
修改文档也有两种方式:
- 全量修改:直接覆盖原来的文档
- 局部修改:修改文档中的部分字段
全量修改
-
全量修改是覆盖原来的文档,本质上是删除原来的文档,然后新增一个相同id的文档,如果id不存在,也会新增一个新的文档。
-
语法如下:
PUT /{索引库名}/_doc/文档id {"字段1": "值1","字段2": "值2",// ... 略 }
局部修改
-
局部修改是只修改指定id匹配的文档中的部分字段
-
语法:
POST /{索引库名}/_update/文档id {"doc": {"字段名": "新的值",} }
批处理
- Elasticsearch中允许通过一次请求中携带多次文档操作,也就是批量处理,语法格式如下:
POST _bulk { "index" : { "_index" : "test", "_id" : "1" } } { "field1" : "value1" } { "delete" : { "_index" : "test", "_id" : "2" } } { "create" : { "_index" : "test", "_id" : "3" } } { "field1" : "value3" } { "update" : {"_id" : "1", "_index" : "test"} } { "doc" : {"field2" : "value2"} } - 其中,index表示新增操作。
