ElasticSearch大集合

ElasticSearch

Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。Elasticsearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。官方客户端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和许多其他语言中都是可用的。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也是基于Lucene

演示:京东,淘宝

重要特性:

  1. 分布式的实时文件存储,每个字段都被索引并可被搜索
  2. 实时分析的分布式搜索引擎
  3. 可以扩展到上百台服务器,处理PB级结构化或非结构化数据

倒排索引

倒排索引的概念是基于MySQL这样的正向索引而言的。

什么是正向索引

如果用id索引一个表,如果是根据id查询,那么直接走索引,查询速度非常快。

但如果是基于表做模糊查询,只能是逐行扫描数据,流程如下:

先扫描id为一的,要一个一个获取数据,要进行全表查询,随着数据量增加,其查询效率也会越来越低。当数据量达到数百万时,就是一场灾难。

什么是倒排索引

倒排索引中有两个非常重要的概念:

  • 文档( Document ):用来搜索的数据,其中的每一条数据就是一个文档。例如一个网页、一个商品信息
  • 词条( Term ):对文档数据或用户搜索数据,利用某种算法分词,得到的具备含义的词语就是词条。例如:我是中国人,就可以分为:我、是、中国人、中国、国人这样的几个词条

创建倒排索引是对正向索引的一种特殊处理,流程如下:

  • 将每一个文档的数据利用算法分词,得到一个个词条
  • 创建表,每行数据包括词条、词条所在文档id、位置等信息
  • 因为词条唯一性,可以给词条创建索引,例如hash表结构索引
id title price
1 小米手机 3999
2 华为手机 4999
3 华为小米充电器 89
4 小米手环 299
正向索引
词条(term) 文档id
小米 1,3,4
手机 1,2
华为 2,3
充电器 3
手环 4
倒排索引

倒排索引的搜索流程如下(以搜索"华为手机"为例):

  1. 用户输入条件 “华为手机” 进行搜索。
  2. 对用户输入内容分词,得到词条: 华为 、 手机 。
  3. 拿着词条在倒排索引中查找,可以得到包含词条的文档id:1、2、3。
  4. 拿着文档id到正向索引中查找具体文档。
正向和倒排

那么为什么一个叫做正向索引,一个叫做倒排索引呢?

  • 正向索引是最传统的,根据id索引的方式。但根据词条查询时,必须先逐条获取每个文档,然后判断文档中是否包含所需要的词条,是根据文档找词条的过程
  • 倒排索引则相反,是先找到用户要搜索的词条,根据词条得到保护词条的文档的id,然后根据id获取文档。是根据词条找文档的过程

正向索引

  • 优点:
    • 可以给多个字段创建索引
    • 根据索引字段搜索、排序速度非常快
  • 缺点:
    • 根据非索引字段,或者索引字段中的部分词条查找时,只能全表扫描。

倒排索引

  • 优点:
    • 根据词条搜索、模糊搜索时,速度非常快
  • 缺点:
    • 只能给词条创建索引,而不是字段
    • 无法根据字段做排序

ES的一些概念

elasticsearch中有很多独有的概念,与mysql中略有差别,但也有相似之处。

文档和字段

elasticsearch是面向文档Document)存储的,可以是数据库中的一条商品数据,一个订单信息。文档数据会被序列化为json格式后存储在elasticsearch中:

ElasticSearch大集合_第1张图片

而Json文档中往往包含很多的字段Field),类似于数据库中的列。

索引和映射

索引(index),就是相同类型的文档的集合

例如:

  • 所有用户文档,就可以组织在一起,称为用户的索引;
  • 所有商品的文档,可以组织在一起,称为商品的索引;
  • 所有订单的文档,可以组织在一起,称为订单的索引;

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/f5b81a4485134745a463a497e8af8d88.png#pic_centerElasticSearch大集合_第2张图片

因此,我们可以把索引当做是数据库中的表

数据库的表会有约束信息,用来定义表的结构、字段的名称、类型等信息。因此,索引库中就有映射mapping),是索引中文档的字段约束信息,类似表的结构约束

mysql与elasticsearch

我们统一的把mysql与elasticsearch的概念做一下对比:

MySQL Elasticsearch 说明
Table Index 索引(index),就是文档的集合,类似数据库的表(table)
Row Document 文档(Document),就是一条条的数据,类似数据库中的行(Row),文档都是JSON格式
Column Field 字段(Field),就是JSON文档中的字段,类似数据库中的列(Column)
Schema Mapping Mapping(映射)是索引中文档的约束,例如字段类型约束。类似数据库的表结构(Schema)
SQL DSL DSL是elasticsearch提供的JSON风格的请求语句,用来操作elasticsearch,实现CRUD
  • Mysql:擅长事务类型操作,可以确保数据的安全和一致性
  • Elasticsearch:擅长海量数据的搜索,分析,计算

因此在企业中,往往是两者结合使用:

  • 对安全性要求较高的写操作,使用mysql实现
  • 对查询性能要求较高的搜索需求,使用elasticsearch实现
  • 两者再基于某种方式,实现数据的同步,保证一致性
IK分词器

分词器的作用是什么?

  • 创建倒排索引时对文档分词
  • 用户搜索时,对输入的内容分词

IK分词器有几种模式?

  • ik_smart:智能切分,粗粒度
  • ik_max_word:最细切分,细粒度
索引库操作

索引库就类似数据库表,mapping映射就类似表的结构。

我们要向es中存储数据,必须先创建“库”和“表”。

mapping映射属性

mapping是对索引库中文档的约束,常见的mapping属性包括:

  • type:字段数据类型,常见的简单类型有:
    • 字符串:text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址)
    • 数值:long、integer、short、byte、double、flfloat、
    • 布尔:boolean
    • 日期:date
    • 对象:object
  • index:是否创建索引,默认为true
  • analyzer:使用哪种分词器
  • properties:该字段的子字段

例如下面的json文档:

{
	"age": 18,
	"weight": 70.2,
	"isMarried": false,
	"info": "apesourceJavaEE王讲师",
	"email": "[email protected]",
	"score": [99.1, 99.5, 98.9],
	"name": {
		"firstName": "师傅",
		"lastName": "王"
	}
}

对应的每个字段映射(mapping):

  • age:类型为 integer;参与搜索,因此需要index为true;无需分词器
  • weight:类型为flfloat;参与搜索,因此需要index为true;无需分词器
  • isMarried:类型为boolean;参与搜索,因此需要index为true;无需分词器
  • info:类型为字符串,需要分词,因此是text;参与搜索,因此需要index为true;分词器可以用ik_smart
  • email:类型为字符串,但是不需要分词,因此是keyword;不参与搜索,因此需要index为false;无需分词器
  • score:虽然是数组,但是我们只看元素的类型,类型为flfloat;参与搜索,因此需要index为true;无需分词器
  • name:类型为object,需要定义多个子属性
    • name.fifirstName;类型为字符串,但是不需要分词,因此是keyword;参与搜索,因此需要index为true;无需分词器
    • name.lastName;类型为字符串,但是不需要分词,因此是keyword;参与搜索,因此需要index为true;无需分词器
创建索引库和映射

基本语法:

  • 请求方式:PUT
  • 请求路径:/索引库名,可以自定义
  • 请求参数:mapping映射

示例:

{
    "mappings": {
        "properties":{
            "age": {
                "type":"integer"
            },
            "weight": {
                "type":"float"
            },
            "isMarried": {
                "type":"boolean"
            },
            "info": {
                "type":"text",
                "analyzer":"ik_smart"
            },
            "email": {
                "type":"keyword",
                "index":"false"
            },
            "name": {
                "properties": {
                    "firstName": {
                        "type":"keyword"
                    }
                }
            }
        }
    }
}
查询数据库

基本语法:

  • 请求方式:GET
  • 请求路径:/索引库名
  • 请求参数:无

格式:

GET /索引库名
修改索引库

倒排索引结构虽然不复杂,但是一旦数据结构改变(比如改变了分词器),就需要重新创建倒排索引,这简直是灾难。因此索引库一旦创建,无法修改mapping。

虽然无法修改mapping中已有的字段,但是却允许添加新的字段到mapping中,因为不会对倒排索引产生影响。

语法说明

PUT /索引库名/_mapping
{
	"properties": {
		"新字段名":{
			"type": "integer"
		}
	}
}
删除索引库

语法:

  • 请求方式:DELETE
  • 请求路径:/索引库名
  • 请求参数:无

格式:

DELETE /索引库名

总结:

  • 创建索引库:PUT /索引库名
  • 查询索引库:GET /索引库名
  • 删除索引库:DELETE /索引库名
  • 添加字段:PUT /索引库名/_mapping
文档操作
新增文档:

语法:

POST /索引库名/_doc/文档id
{
	"字段1": "值1",
	"字段2": "值2",
	"字段3": {
		"子属性1": "值3",
		"子属性2": "值4"
	},
	// ...
}

示例:

POST /apesource/_doc/1
{
	"info": "apesource程序员Java讲师",
	"email": "[email protected]",
	"name": {
		"firstName": "师傅",
		"lastName": "王"
	}
}
查询文档:

根据rest风格,新增是post,查询应该是get,不过查询一般都需要条件,这里我们把文档id带上。

语法:

GET /{索引库名称}/_doc/{id}
删除文档:

删除使用DELETE请求,同样,需要根据id进行删除:

语法:

DELETE /{索引库名}/_doc/id值
修改文档:

修改有两种方式:

  • 全量修改:直接覆盖原来的文档
  • 增量修改:修改文档中的部分字段

注意:如果根据id删除时,id不存在,第二步的新增也会执行,也就从修改变成了新增操作了。

语法:

PUT /{索引库名}/_doc/文档id
{
	"字段1": "值1",
	"字段2": "值2",
	// ... 略
}

示例:

PUT /apesource/_doc/1
{
	"info": "java程序员高级Java讲师",
	"email": "[email protected]",
	"name": {
		"firstName": "师傅",
		"lastName": "王"
	}
}

增量修改:

增量修改是只修改指定id匹配的文档中的部分字段。

语法:

POST /{索引库名}/_update/文档id
{
	"doc": {
		"字段名": "新的值",
	}
}

示例:

POST /apesource/_update/1
{
	"doc": {
		"email": "[email protected]"
	}
}

总结:

  • 创建文档:POST /{索引库名}/_doc/文档id { json文档 }
  • 查询文档:GET /{索引库名}/_doc/文档id
  • 删除文档:DELETE /{索引库名}/_doc/文档id
  • 修改文档:
    • 全量修改:PUT /{索引库名}/_doc/文档id { json文档 }

**增量修改:**

增量修改是只修改指定id匹配的文档中的部分字段。

**语法:**

```json
POST /{索引库名}/_update/文档id
{
	"doc": {
		"字段名": "新的值",
	}
}

示例:

POST /apesource/_update/1
{
	"doc": {
		"email": "[email protected]"
	}
}

总结:

  • 创建文档:POST /{索引库名}/_doc/文档id { json文档 }
  • 查询文档:GET /{索引库名}/_doc/文档id
  • 删除文档:DELETE /{索引库名}/_doc/文档id
  • 修改文档:
    • 全量修改:PUT /{索引库名}/_doc/文档id { json文档 }
    • 增量修改:POST /{索引库名}/_update/文档id { “doc”: {字段}}

你可能感兴趣的:(elasticsearch,大数据,搜索引擎)