ElasticSearch全文搜索引擎之核心概念和IK分词器篇

一、概述

在前面一篇文章的学习中,我们已经掌握了es是什么,同时也把es的服务已经安装启动,那么es是如何去存储数据,数据结构是什么,又是如何实现搜索的呢?

elasticSearch是面向文档的,关系型数据库和elasticsearch客观对比如下表所示:

Relational DBElasticSearch
数据库database索引index
表tables类型types(慢慢会被弃用)
行rows文档document
字段fieldsfields

elasticsearch集群中可以包含多个索引(数据库),每个索引中可以包含多个类型(表),每个类型下又包含多个文档(行),每个文档中又包含多个字段(列)。

elasticsearch物理设计:

elasticsearch在后台把每个索引划分成多个分片,每个分片可以在集群中的不同服务器间迁移。一个节点就是集群,默认的集群名称就是elasticsearch,如下图可以看到。

elasticsearch逻辑设计:

一个索引类型中,可以包含多个文档,比如说文档1、文档2......,当我们索引一篇文档时,可以通过如下的顺序找到它:

索引index  > 类型types > 文档ID

通过上面的组合我们就能索引到某个具体的文档。

注意:文档ID不必是整数,实际上是个字符串。

二、elasticsearch相关术语

下面来看看elasticsearch中几个重要的术语:

【a】文档document

elasticsearch是面向文档的,那么就意味着索引和搜索数据的最小单位是文档,文档会被序列化为JSON格式,保存在Elasticsearch中。

文档有几个重要属性:

  1. 自我包含,一个文档同时包含字段和对应的值,也就是同时包含key:value;
  2. 可以使层次型的,一个文档汇总包含自文档,复杂的逻辑实体就是这样来的,其实就是一个json对象;
  3. 灵活地结构,文档不依赖预先定义的模式,我们知道关系型数据库中,要提前定义字段才能使用,在es中,对于字段是非常灵活地,有时候,我们可以忽略该字段,或者动态的添加一个新的字段;
  4. 每个文档都有一个 Unique ID;

【b】类型type

类型是文档的逻辑容器,就像关系型数据库一样,表格式行的容器。类型中对于字段的定义成为映射,比如name映射为字符串类型。type表示某个索引下面的某种相同数据结构的结合。在较低版本的ES中,一个索引中可以有多个type,高版本中一个索引下只能有一个类型,官方建议每个索引下最好只有一个type。如果一个index下有多个type,在不同的搜索场景下可能会相互有影响,比如:一个索引下面有一个用于统计分析的type和一个用于搜索的type,如果统计请求比较慢,有可能会阻塞到查询请求。

所以最安全的做法还是:提前定义好所需要的的映射,然后再使用。这样es就不会在那里猜字段是什么类型的。

【c】索引index

索引是文档的容器,即多个有相似结构的文档数据的集合,类似于MySQL数据库中的数据库概念。

【d】集群cluster

集群表示由多个节点组成的ES集群(常见集群种类:HA,HB,HP)。集群有一个名称,默认是elasticsearch,集群最小节点数可以为1个。

我们可以在config/elasticsearch.yml里定制我们的集群的名字:

【e】节点node

集群中的节点,其实就是一个 Elasticsearch 的实例(本质上就是一个 JAVA 进程)。节点也有自己的名称,默认是随机分配的,默认情况下,节点启动之后,会自动去寻找名称为cluster.name字段所指定的集群。如果在默认不修改cluster.name的情况下,启动多个节点之后,它们会自动组成一个ES集群。

节点主要有以下特性:

  1. 一台机器上可以运行多个 Elasticsearch 进程,但是生产环境一般建议一台机器上只运行一个 Elasticsearch 实例;
  2. 每一个节点都有名字,通过配置文件配置,或者启动的时候 -e node.name=node1 来指定;
  3. 每一个节点在启动之后,会分配一个 UID,保存在 data 目录下;

【e】shard

在elasticsearch中,每个索引会被拆分为多个shard分片,每个shard就会存放这个index的一部分数据,shard会散落在多台服务器上。有了shard分片就可以进行横向扩展,存储更多数据,让搜索和分析等操作分布到多台服务器上去执行,提升吞吐量和性能。

shard又分为replica shard和primary shard,每个shard都是一个lucene index。

  • primary shard主分片:用以解决数据水平扩展的问题,通过主分片,可以将数据分布到集群内的所有节点上。建立索引时一次设置,不能修改(后续不允许修改,除非 Rdindex),默认是5个;
  • replica shard副本分片:每个服务器随时可能故障或宕机,此时shard就可以会丢失,因此可以为每一个shard创建多个replica副本。replica可以在shard故障时提供备用服务,保证数据不丢失或者丢失很少,多个replica还可以提升搜索操作的吞吐量和性能。副本分片可以动态调整,默认是1个。

默认每个索引10个shard,即5个primary shard主分片,5个replica shard副本,最小的高可用配置是2台服务器。

一个集群中至少有一个节点,而一个节点就是一个elasticsearch进程,节点可以有多个索引,如果你创建索引,那么索引默认将会有5个分片(primary shard,又称为主分片)构成,每一个主分片会有一个副本(replica shard,又称为复制分片)。

实际上,一个分片是一个Lucene索引,一个包含倒排索引的文件目录,倒排索引的结构使得elasticsearch在不扫描全部文档的情况下,就能告诉我们哪些文档包含特定的关键字。那么,什么是倒排索引呢?

  • 倒排索引

elasticsearch使用的是一种称为倒排索引的结构,采用Lucene倒排索引作为底层,这种结构适用于快速的全文搜索,一个索引由文档中所有不重复的列表来构成,对于每一个词,都有一个包含它的文档列表。

我们来看一个示例,比如我们通过博客标签来搜索博客文章。那么倒排索引列表就是这样的一个结构:

原始数据:

博客文章ID标签
1python
2python
3linux,python
4linux

倒排索引:

标签博客文章
python1,2,3
linux3,4

如果要搜索含有python标签的文章,那相对于查找所有原始数据而言,查找倒排索引后的数据将会快得多。只需要查看标签这一栏,然后获取相关的文章ID即可。

三、IK分词器

  • 什么是IK分词器?

分词:即把一段中文或者别的划分成一个个的关键字,我们在搜索时候回把自己的信息进行分词,会把数据库中或者索引库中的数据进行分词,然后进行一个匹配操作,默认的中文分词是将每个字看成一个词,比如"我爱中国"会被分词为:"我","爱","中","国",这显然是不符合要求的,所以我们需要安装中文分词器IK来解决这个问题。

如果要使用中文,建议使用IK分词器。

IK提供了两个分词算法:ik_smart 和ik_max_word,其中ik_smart为最少切分,ik_max_word为最细粒度划分。

下面我们就需要安装IK分词器:

【a】下载地址

https://github.com/medcl/elasticsearch-analysis-ik,这里笔者下载的是elasticsearch-analysis-ik-7.6.1.zip。

【b】下载完毕之后,将其放入我们的elasticsearch的插件中即可。

解压缩到当前目录中,放入ik文件夹中,如下图:

 【c】重启Elasticsearch

 可以看到我们的IK分词器插件已经成功加载。

执行elasticsearch-plugin list命令,同样看到,当前es中找到了IK分词器插件。

 【d】启动kibana进行测试

打开kibana控制台,我们首先测试一下IK分词器的ik_smart最少切分策略。

GET _analyze
{
  "analyzer": "ik_smart",
  "text": "中国共产党"
}

可以看到,使用ik_smart最少切分策略时,kibana只帮我们分词为一个"中国共产党"一个词。 

{
  "tokens" : [
    {
      "token" : "中国共产党",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "CN_WORD",
      "position" : 0
    }
  ]
}

 下面我们修改成ik_max_word最细粒度划分策略看看效果如何:

GET _analyze
{
  "analyzer": "ik_max_word",
  "text": "中国共产党"
}

如下就是IK分词器使用ik_max_word分词后的结果:

{
  "tokens" : [
    {
      "token" : "中国共产党",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "CN_WORD",
      "position" : 0
    },
    {
      "token" : "中国",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "CN_WORD",
      "position" : 1
    },
    {
      "token" : "国共",
      "start_offset" : 1,
      "end_offset" : 3,
      "type" : "CN_WORD",
      "position" : 2
    },
    {
      "token" : "共产党",
      "start_offset" : 2,
      "end_offset" : 5,
      "type" : "CN_WORD",
      "position" : 3
    },
    {
      "token" : "共产",
      "start_offset" : 2,
      "end_offset" : 4,
      "type" : "CN_WORD",
      "position" : 4
    },
    {
      "token" : "党",
      "start_offset" : 4,
      "end_offset" : 5,
      "type" : "CN_CHAR",
      "position" : 5
    }
  ]
}

 可以看到,IK分词器穷尽词库的可能,切分成了几个词。

下面我们再次修改一下分词的text:

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" : 3,
      "type" : "CN_WORD",
      "position" : 1
    },
    {
      "token" : "迪",
      "start_offset" : 3,
      "end_offset" : 4,
      "type" : "CN_CHAR",
      "position" : 2
    },
    {
      "token" : "丽",
      "start_offset" : 4,
      "end_offset" : 5,
      "type" : "CN_CHAR",
      "position" : 3
    },
    {
      "token" : "热",
      "start_offset" : 5,
      "end_offset" : 6,
      "type" : "CN_CHAR",
      "position" : 4
    },
    {
      "token" : "巴",
      "start_offset" : 6,
      "end_offset" : 7,
      "type" : "CN_CHAR",
      "position" : 5
    }
  ]
}

由上面的分词结果可以发现,"迪丽热巴"是一个明星的名字,有时候,我们在分词的时候并不想拆分他们,只想"迪丽热巴"作为一个关键字进行搜索。

 解决方法:将不希望进行分词的词,需要我们自己加入到分词器的字典中。

 首先进入到es目录的插件目录下,找到config目录里面的IKAnalyzer.cfg.xml配置文件,往里面添加我们自己的词即可。

 新建dilireba.dic文件,在里面加入"迪丽热巴",如下图:

保存之后,需要将我们的配置文件配置在IKAnalyzer.cfg.xml中:

 接下来,我们需要重启es、es-head和kibana:

从es的启动日志中可以看到我们自己定义的dilireba.dic字段已经被加载,重启完成后,重新测试"我爱迪丽热巴"进行分词:

{
  "tokens" : [
    {
      "token" : "我",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "CN_CHAR",
      "position" : 0
    },
    {
      "token" : "喜欢",
      "start_offset" : 1,
      "end_offset" : 3,
      "type" : "CN_WORD",
      "position" : 1
    },
    {
      "token" : "迪丽热巴",
      "start_offset" : 3,
      "end_offset" : 7,
      "type" : "CN_WORD",
      "position" : 2
    }
  ]
}

可以看到,"迪丽热巴"成了一个词,es在解析的时候不会将它进行拆分,这在实际工作中很有用。 

小总结:以后我们需要自己配置分词,那么就在自己定义的dic文件中进行配置即可。

四、总结

本篇文章主要介绍了elasticsearch中几个重要的概念:索引、类型、文档、集群、节点、分片(主分片、副本分片)等,并介绍了一款常用的中文分词器插件 - IK分词器,通过示例详细介绍了IK分词器两种不同的分词策略,总结了如何自定义自己的词到我们的分词器字典中。下面文章将会介绍elasticsearch常用的REST操作等。由于笔者水平有限,文中可能有不对之处,还望大家指正,相互学习,一起进步!

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页
实付 19.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值