关于ElasticSearch

关系型数据库搜索出现的问题

要实现类似百度的复杂搜索,或者京东的商品搜索,如果使用传统的数据库存储数据,那么会存在一系列的问题:

  • 性能瓶颈:当数据量越来越大时,数据库搜索的性能会有明显下降。虽然可以通过分库分表来解决存储问题,但是性能问题并不能彻底解决,而且系统复杂度会提高、可用性下降。
  • 复杂业务:百度或京东的搜索往往需要复杂的查询功能,例如:拼音搜索、错字的模糊搜索等。这些功能用数据库搜索难以实现,或者实现复杂度较高
  • 并发能力:数据库是磁盘存储,虽然也有缓存方案,但是并不实用。因此数据库的读写并发能力较差,难以应对高并发场景

但是,并不是说数据库就一无是处。在一些对业务有强数据一致性需求,事物需求的情况下,数据库是不可替代的。

只是在海量数据的搜索方面,需要有新的技术来解决,就是我们今天要学习的倒排索引技术。

什么是倒排索引?倒排索引的原理:

倒排索引的数据存储方式与数据库类似,但检索方式不同。

全文检索主要是通过倒排索引的方式实现,倒排索引主要是分成两大步骤完成:

  1. 数据按照规则(分词)处理完成后存储到索引库
  2. 用户输入关键词按照规则处理完成后在索引库中检索

首先,倒排索引需要把文档数据逐个编号(从0递增),存储到文档表中。并且给每一个编号创建索引,这样根据编号检索文档的速度会非常快。

然后,对文档中的数据按照算法做分词,得到一个个的词条,记录词条和词条出现的文档的编号、位置、频率信息
在这里插入图片描述
在这里插入图片描述
然后给词条创建索引,这样根据词条匹配和检索的速度就非常快。

检索数据过程

1)用户输入条件"谷歌创始人跳槽"进行搜索。

2)对用户输入内容分词,得到词条:谷歌创始人跳槽

3)拿着词条到词条列表中查找,可以得到包含词条的文档编号:0、1、2、3、4。

4)拿着词条的编号到文档列表中查找具体文档。
在这里插入图片描述
虽然搜索会在两张表进行,但是每次都是根据索引查找,因此速度比传统搜索时的全表扫描速度要快的多。

其实用白话来说就是,将一段话按照词语的方式打散,然后一个词一个词的放入倒排索引库。查找的时候会根据词条查找出对应的文档编号,然后将符合的文档数据筛选出来。

ElasticSearch:

Elasticsearch是一个基于Lucene的搜索web服务,对外提供了一系列的Rest风格的API接口。因此任何语言的客户端都可以通过发送Http请求来实现ElasticSearch的操作

ES的主要优势特点如下:

  • 速度快:Elasticsearch 很快,快到不可思议。我们通过有限状态转换器实现了用于全文检索的倒排索引,实现了用于存储数值数据和地理位置数据的 BKD 树,以及用于分析的列存储。而且由于每个数据都被编入了索引,因此您再也不用因为某些数据没有索引而烦心。您可以用快到令人惊叹的速度使用和访问您的所有数据。实现近实时搜索,海量数据更新在Elasticsearch中几乎是完全同步的。
  • 扩展性高:可以在笔记本电脑上运行,也可以在承载了 PB 级数据的成百上千台服务器上运行。原型环境和生产环境可无缝切换;无论 Elasticsearch 是在一个节点上运行,还是在一个包含 300 个节点的集群上运行,您都能够以相同的方式与 Elasticsearch 进行通信。它能够水平扩展,每秒钟可处理海量事件,同时能够自动管理索引和查询在集群中的分布方式,以实现极其流畅的操作。天生的分布式设计,很容易搭建大型的分布式集群(solr使用Zookeeper作为注册中心来实现分布式集群)
  • 强大的查询和分析:通过 Elasticsearch,您能够执行及合并多种类型的搜索(结构化数据、非结构化数据、地理位置、指标),搜索方式随心而变。先从一个简单的问题出发,试试看能够从中发现些什么。找到与查询最匹配的 10 个文档是一回事。但如果面对的是十亿行日志,又该如何解读呢?Elasticsearch 聚合让您能够从大处着眼,探索数据的趋势和模式。如全文检索,同义词处理,相关度排名,复杂数据分析。
  • 操作简单:客户端API支持Restful风格,简单容易上手。

ElasticSearch及相关组件在虚拟机中安装

安装命令:

docker run -id --name elasticsearch \
    -e "cluster.name=elastic-cluster" \
    -e "http.host=0.0.0.0" \
    -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
    -e "discovery.type=single-node" \
    -e http.cors.enabled=true \
    -e http.cors.allow-origin="*" \
    -e http.cors.allow-headers=X-Requested-With,X-Auth-Token,Content-Type,Content-Length,Authorization \
    -e http.cors.allow-credentials=true \
    -v es-data:/usr/share/elasticsearch/data \
    -v es-logs:/usr/share/elasticsearch/logs \
    -v es-plugins:/usr/share/elasticsearch/plugins \
    --privileged \
    --restart=always \
    --hostname elasticsearch \
    -p 9200:9200 \
    -p 9300:9300 \
elasticsearch:7.4.2

命令解释:

  • -e "cluster.name=es-docker-cluster":设置集群名称
  • -e "http.host=0.0.0.0":监听的地址,可以外网访问
  • -e "ES_JAVA_OPTS=-Xms512m -Xmx512m":内存大小
  • -e "discovery.type=single-node":非集群模式
  • -v es-data:/usr/share/elasticsearch/data:挂载逻辑卷,绑定es的数据目录
  • -v es-logs:/usr/share/elasticsearch/logs:挂载逻辑卷,绑定es的日志目录
  • -v es-plugins:/usr/share/elasticsearch/plugins:挂载逻辑卷,绑定es的插件目录
  • --privileged:授予逻辑卷访问权
  • -p 9200:9200:端口映射配置

如果已经启动的容器项目,则使用update更新:

docker update --restart=always 容器名/ID

防火墙配置(可选):

# 开放端口 9200  9300 5601
firewall-cmd --zone=public --add-port=9200/tcp --permanent
# 重启防火墙
firewall-cmd --reload
# 查看放行端口
firewall-cmd --list-ports

Kibana:

Kibana是一个基于Node.js的Elasticsearch索引库数据统计工具,可以利用Elasticsearch的聚合功能,生成各种图表,如柱形图,线状图,饼图等。

而且还提供了操作Elasticsearch索引数据的控制台,并且提供了一定的API提示。

安装Kibana

docker run -di --name kibana   -p 5601:5601  -e ELASTICSEARCH_HOSTS=http://YourIP:9200 kibana:7.4.2

安装完毕之后
输入地址访问:http://YourIP:5601

分词器

ElasticSearch 内置分词器

  • Standard Analyzer - 默认分词器,按词切分,小写处理
  • Simple Analyzer - 按照非字母切分(符号被过滤), 小写处理
  • Stop Analyzer - 小写处理,停用词过滤(the,a,is)
  • Whitespace Analyzer - 按照空格切分,不转小写
  • Keyword Analyzer - 不分词,直接将输入当作输出
  • Patter Analyzer - 正则表达式,默认\W+(非字符分割)
  • Language - 提供了30多种常见语言的分词器

但是默认的分词器并不能处理中文,所以一般会用第三方分词器

IK分词器

IKAnalyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包,是一个基于Maven构建的项目,具有60万字/秒的高速处理能力,支持用户词典扩展定义。

IK分词器的 地址:https://github.com/medcl/elasticsearch-analysis-ik, 安装非常简单。

IK分词器可以用ik_max_wordik_smart两种方式,分词粒度不同。

安装IK分词器
1、进入/var/lib/docker/volumes/es-plugins/_data/

cd /var/lib/docker/volumes/es-plugins/_data/

2、新建文件目录 ik 并且进入

mkdir ik
cd ik

3、解压elasticsearch-analysis-ik-7.4.2.zip

yum -y install unzip 
unzip elasticsearch-analysis-ik-7.4.2.zip

4、重启容器

docker restart elasticsearch

5、重启 Kibana

docker restart kibana

测试后发现后

  • ik_smart:最小切分

  • ik_max_word:最细切分

扩展词词典

1)打开IK分词器config目录:

2)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>
         <!--用户可以在这里配置自己的扩展停止词字典-->
        <entry key="ext_stopwords"></entry>
        <!--用户可以在这里配置远程扩展字典 -->
        <!-- <entry key="remote_ext_dict">words_location</entry> -->
        <!--用户可以在这里配置远程扩展停止词字典-->
        <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

3)新建一个 ext.dic,可以参考config目录下复制一个配置文件进行修改,里面放入自定义的扩展词

4)重启elasticsearch

docker restart elasticsearch
docker restart kibana

# 查看 日志
docker logs -f elasticsearch

注意当前文件的编码必须是 UTF-8 格式

停用词词典
1)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>
         <!--用户可以在这里配置自己的扩展停止词字典  *** 添加停用词词典-->
        <entry key="ext_stopwords">stopword.dic</entry>
        <!--用户可以在这里配置远程扩展字典  -->
        <!-- <entry key="remote_ext_dict">words_location</entry> -->
        <!--用户可以在这里配置远程扩展停止词字典-->
        <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

3)在 stopword.dic 添加停用词

以下步骤同上

Elasticsearch对比MySQL

在这里插入图片描述

因此,我们对ES的操作,就是对索引库、类型映射、文档数据的操作:

  • 索引库操作:主要包含创建索引库、查询索引库、删除索引库等
  • 类型映射操作:主要是创建类型映射、查看类型映射
  • 文档操作:文档的新增、修改、删除、查询

Elasticsearch的索引库操作

创建索引库
创建索引库的请求格式:

  • 请求方式:PUT

  • 请求路径:/索引库名

  • 请求参数:格式:

在这里插入图片描述

查询索引库

  • 请求方式:GET

  • 请求路径:/索引库名

  • 请求参数:无

格式:
GET /索引库名

删除索引库

  • 请求方式:DELETE

  • 请求路径:/索引库名

  • 请求参数:无

格式:

DELETE /索引库名

mapping映射

MySQL中有表,并且表中有对字段的约束,对应到elasticsearch中就是类型映射mapping.

elasticsearch字段的映射属性该怎么选,除了字段名称外,我们一般要考虑这样几个问题:

  • 1)数据的类型是什么?

    • 这个比较简单,根据字段的含义即可知道,可以通过type属性来指定
  • 2)数据是否参与搜索? 是否索引

    • 参与搜索的字段将来需要创建倒排索引,作为搜索字段。可以通过index属性来指定是否参与搜索,默认为true,也就是每个字段都参与搜索
  • 3)数据是否需要分词? 是否分词

    • 一个字段的内容如果不是一个不可分割的整体,例如国家,一般都需要分词存储。

      • 如果是身份证号则不需要分词

      • 如果分词的话用什么分词器?

        • 分词器类型很多,中文一般选择IK分词器

        • 指定分词器类型可以通过analyzer属性指定

        注意:在同一个域上 分词和搜索时 建议使用同一个分词器

  • 4)数据是否存储到es库中 是否存储

    • 是否存储取决于用户是否需要将当前字段展示给用户查看

**elasticsearch字段的映射属性是重点,直接决定了你的字段创立是否正确

数据类型

  • string类型,又分两种:

    • text:可分词,存储到elasticsearch时会根据分词器分成多个词条
    • keyword:不可分词,数据会完整的作为一个词条
  • Numerical:数值类型,分两类

    • 基本数据类型:long、interger、short、byte、double、float、half_float
    • 浮点数的高精度类型:scaled_float
      • 需要指定一个精度因子,比如10或100。elasticsearch会把真实值乘以这个因子后存储,取出时再还原。
  • Date:日期类型

  • Object:对象,对象不便于搜索。因此ES会把对象数据扁平化处理再存储。

创建类型映射(索引库已存在)

  • 语法

请求方式依然是PUT

PUT /索引库名/_mapping
{
  "properties": {
    "字段名1": {
      "type": "类型",
      "index": true"analyzer": "分词器"
    },
    "字段名2": {
      "type": "类型",
      "index": true"analyzer": "分词器"
    },
    ...
  }
}

类型名称:就是前面将的type的概念,类似于数据库中的表
字段名:任意填写,下面指定许多属性,例如:

  • type:类型,可以是text、long、short、date、integer、object等
  • index:是否参与搜索,默认为true
  • analyzer:分词器

创建类型映射(索引库不存在)

PUT /索引库名
{
	"mappings":{
      "properties": {
        "字段名1": {
          "type": "类型",
          "index": true"analyzer": "分词器"
        },
        "字段名2": {
          "type": "类型",
          "index": true"analyzer": "分词器"
        },
        ...
      }
    }
}

查看映射关系

  • 语法:
GET /索引库名/_mapping

Document文档的操作

新增文档

  • 语法:
POST /{索引库名}/_doc
{
    "key":"value"
}
  • 示例:
# 新增文档数据
POST /heima/_doc
{
    "title":"小米手机",
    "images":"http://image.leyou.com/12479122.jpg",
    "price":2699.00
}
  • 响应:
{
  "_index" : "xxx",
  "_type" : "_doc",
  "_id" : "rGFGbm8BR8Fh6kyTbuq8",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

结果解释:

  • _index:新增到了哪一个索引库。
  • _id:这条文档数据的唯一标示,文档的增删改查都依赖这个id作为唯一标示。此处是由ES随即生成的,我们也可以指定使用某个ID
  • result:执行结果,可以看到结果显示为:created,说明文档创建成功。

新增并指定id

  • 语法:
POST /{索引库名}/_doc/{id}
{
    "key":"value"
}

查询文档,根据ID查询
语法:

GET /{索引库名称}/_doc/{id}

词条查询

词条查询不会分析查询条件,只有当词条和查询字符串完全匹配时才匹配搜索。
语法:

GET /{索引库}/_search
{
  "query": {
    "term": {
      "field字段": {
        "value": "查询的关键词"
      }
    }
  }
}

全文查询

全文查询会分析查询条件,先将查询条件进行分词,然后查询,求并集

语法:

GET /{索引库}/_search
{
  "query": {
    "match": {
      "查询的字段":"查询关键词"
    }
  }
}

查询所有文档
语法:

# 查询所有
GET /heima/_search
{
  "query": {
    "match_all": {}
  }
}

修改文档

把刚才新增的请求方式改为PUT,就是修改了。不过修改必须指定id,

  • id对应文档存在,则修改
  • id对应文档不存在,则新增

删除文档

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

  • 语法:
DELETE /索引库名/类型名/id值
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值