ElasticSearch 搜索引擎

简称es,是类似于mysql但是专注于搜索的一种数据库。在elastic stack中占据重要地位。

 


倒排索引:

 我们的数据库都是正向索引,比如根据id查询数据,那么倒排索引是将关键字进行分词,然后将词条和id保存在一张表中,不同数据分词后有相同的词条的话,就会记录在同一条数据中,并且把id放在一个字段,搜索的时候根据词条先搜索出符合的id,然后根据id查询数据。

 


分词器:

下载地址:GitHub - medcl/elasticsearch-analysis-ik: The IK Analysis plugin integrates Lucene IK analyzer into elasticsearch, support customized dictionary.

进去之后点击右边的版本,就能进去下载,

#因为启动es时候 已经做好的目录挂载
容器内部:/usr/share/elasticsearch/plugins 
宿主机:/mydata/elasticsearch/plugins

所以只需要将文件复制到/mydata/elasticsearch/plugins 目录下即可

然后重启es

docker restart elasticsearch

分词器也就是分词的规则,es中有默认的细粒度分词(ik_max_word)和粗粒度分词(ik_smart),细粒度分词比较多,粗粒度分词比较少。

我们也可以自定义我们想要分出来的词和不想被分出来的词,比如我们自己创建的一个品牌名,就可以自己定义一个分词字典,同样的,不想分词的也会有一个字典。

想要分出的词就可以写在我们配置文件中的ext.dic字典,不想分出来的就修改sropword.dic字典

 


mapping 属性

mapping属性实际上就是我们mysql中的一个表结构,比如某个字段是什么类型的啊,有什么约束条件啊什么的。

每创建一个字段都要想下图中的几个条件,什么类型的,是否参与搜索(根据这个判断是否创建倒排索引,默认index为true),使用什么分词器,该字段有没有子字段。


索引:

索引其实对应的就是mysql中的表,es说要创建个索引,就相当于mysql说,要创建一个表。

创建索引示例:

查看和删除索引:

 

修改索引库:

实际上es是不支持修改索引库的,因为带来的影响比较大,尤其是生产环境下。

 但是,虽然不支持修改索引库,但是支持添加一个字段


文档:

 文档,实际上就相当于mysql中的数据。添加文档就是mysql中的添加数据

这里要说一下,mysql中写的语句叫做sql语句,es中写的语句叫做DSL语句。

新增文档:

查看和删除文档:

 

修改文档:

 修改文档实际上有两种方法,一种是全量修改,一种就是新增一个文档:

方式一:他会根据id先找到这个文档,然后删除,再添加新文档

 方式二, 这个就是修改指定的字段,我们可以看到上面的_doc变成了_update ,所以这里就是对某个字段进行修改了

 


es查询语句:

 

 

 查询所有:

这里的查询类型,之后可以根据自己的条件的不断变化,更换不同的查询类型,这里的math_all就是查询所有,所有里面不需要跟条件 

全文检索查询:

 设定的场景就是我们常见的搜索框,根据输入的字段查询匹配的数据。

match是查询某一个字段中是否包含输入的信息,multi_match是同时查询几个字段中是否包含输入的信息。

注意:搜索字段越多,查询效率越低,所以我们尽量用一个字段查,之后会学到copy_to,查询一个字段也可以实现多个字段的效果。

 

 

精确查询:

这里指的就是不被分词的字段,进行精确匹配 ,也就是keyword

包括term和range:  range中gte是大于等于,lte是小于等于     greate/less than equals 

 地理查询:

也就是根据经纬度查询:

第一种,就是geo_bounding_box类型,根据传入的两个经纬度确定两个点,然后分别画横竖两条线,然后围成一个矩形,那么查询出来的结果,就是经纬度在这个矩形当中的数据。

 

 第二种就是geo_distance,这个比较常用,它是根据传入的一个经纬度点和一个距离,以经纬度点为圆心,以距离为半径画圆,查出来的就是经纬度在这个范围中的数据。适合场景,附近的人。

注意,那个距离要写单位.比如:km   m

`        那个经纬度的点是要数据中有个字段,专门表示经纬度,然后用那个字段的名称,然后后面的值进行修改,图中的字段名称就叫做location     (lat 经度    lon   纬度     )

可以分开写,也可以像第二张图中一样用逗号隔开

 

复合查询:

 

相关性算分:这里要明白一个道理就是es会根据匹配度进行数据打分_score,匹配度越高,排序越靠前,并且这个算分可以人工干预。 

Function_score_query:根据这个就可以给我们想要加分的数据进行人工干预。

 

 

Boolean Query:

这种复合查询就是相当于多条件查询,相当于mysql中的and or 

每个关键字都可以定义多个查询条件

 

 


排序:

两种排序,一种是按照字段的值的大小进行升序或者是降序的排序,这种就是常见的大小排序

另一种是根据在某个经纬度的多少距离内的远近排序。这种就是查询附近的酒店那个意思

那么要注意的是,一旦做了排序,那么原来的那个相关性打分就没意义了,所以_score这个字段就变成了null

也可以在排序中写两个,表示当第一个相等时,就按第二个条件进行排序。 

 

分页:

 在es中分页和mybatis中的也差不多,也是根据页数和每页条数进行,在es中的关键字是from 和size

深度分页问题:

 

比如这个图中,从9990查询,查十条是正好10000条的,是不会报错的,但是如果改成9991就会变成10001条,超过了我们的结果集查询上限,那么就会报图中的错。

 解决的办法就是下面两种,第二种不推荐使用,第一种也有不好的地方,只能往后查,不能往前查。

分页小结:

 


高亮处理:

 就是我们的百度的时候,我们查询出来的东西都变成了红色。

 

这里涉及到我们的搜索字段要和高亮字段匹配才能进行高亮,那么如果使用copy_to之后的那个包含了多个字段信息的字段怎么办呢,我们可以手动设置搜索字段和高亮字段不匹配。

就是图中红色框框起来的这段配置。

 

 小结:

 


数据聚合:

 也就是相当于mysql中的group by进行分组之后进行聚合函数。聚合的字段一定是不分词的。

 大致分这么几种,当然还有更多,可以查看es的官方文档

 小结:

利用这个值进行聚合,下面的terms就是这个聚合。

aggs就是DSL语句中聚合的表示。

 查询出来的结果就是一个这样的json格式:buckets就是我们聚合之后的结果,buckets中每一个{}就是一个bucket(桶),doc_count就是这个聚合之后桶内的文档数量,默认是倒序排序

 如果修改默认的聚合排序规则,只要加一个order字段,然后对其进行排序即可

限定聚合范围:

只需要添加一个查询条件就可以,就相当于msyql中group by前面的where

 

 小结:

Metrics聚合方式:也不能算是另一种,就是一部分,也相当于mysql中的max min avg sum等

下图中用了一个聚合的嵌套,外面使用了桶聚合,然后在桶聚合中的每一个桶内,使用了Metrics聚合

添加之后,查询的结果中,每一个桶内就多了几个结果;

 

 如果想对这个结果中的avg的值进行一个排序,那么就要添加order: desc 降序   asc生序


 copy_to:

当我们在做query_string查询的时候 关联多个字段查询3

可以利用copy_to属性完成将多个字段拷贝到一个属性中 简化查询


PUT user
{
  "mappings": {
    "properties": {
      "first_name": {
        "type": "text",
        "copy_to": "full_name" 
      },
      "last_name": {
        "type": "text",
        "copy_to": "full_name" 
      },
      "full_name": {
        "type": "text"
      }
    }
  }
}

总结:

1.copy_to属性可以帮助我们将多个字段或者一个字段拷贝到另外一个字段

2.copy_to属性可以帮助我们简化查询

3.copy_to属性可以帮助我们提高查询速度

自动补全:

 拼音分词器,自动补全要依赖于拼音分词器,提升用户体验

下载地址:GitHub - medcl/elasticsearch-analysis-pinyin: This Pinyin Analysis plugin is used to do conversion between Chinese characters and Pinyin.

 步骤:

1.解压

2.上传到es的插件目录下  就是上面方分词器的那个目录

3.重启es

自定义分词器

默认的拼音分词器会将每个汉字单独分为拼音,而我们希望的是每个词条形成一组拼音,需要对拼音分词器做个性化定制,形成自定义分词器。

elasticsearch中分词器(analyzer)的组成包含三部分:

  • character filters:在tokenizer之前对文本进行处理。例如删除字符、替换字符

  • tokenizer:将文本按照一定的规则切割成词条(term)。例如keyword,就是不分词;还有ik_smart

  • tokenizer filter:将tokenizer输出的词条做进一步处理。例如大小写转换、同义词处理、拼音处理等

文档分词时会依次由这三部分来处理文档:

 

 

声明自定义分词器的语法如下:  

PUT /test
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "ik_max_word",
          "filter": "py"
        }
      },
      "filter": {
        "py": {
          "type": "pinyin",
          "keep_full_pinyin": false,
          "keep_joined_full_pinyin": true,
          "keep_original": true,
          "limit_first_letter_length": 16,
          "remove_duplicated_term": true,
          "none_chinese_pinyin_tokenize": false
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "my_analyzer",
        "search_analyzer": "ik_smart"
      }
    }
  }
}

注意: 拼音分词器适合在创建倒排索引的时候使用,但不能再搜索的时候使用,因为会有拼音相同汉字不同的情况出现。

为避免这种情况,所以我们再创建索引的时候要给字段设置,创建倒排索引的时候使用什么分词器,搜索的时候使用什么分词器。

 小结:

 自动补全,我们的重点来了:

1、自动补全的字段类型是completion,

2、自动补全的字段应该是一个多个词条形成的数组,也就是我们的copy_to的目标字段

 

自动补全的语法:

 

查询结果就是我们的suggest对象,其中的options包括自动补全后的所有信息:

 


数据同步: 

思路分析

 

常见的数据同步方案有三种:

  • 同步调用

  • 异步通知

  • 监听binlog

 方案一:同步调用

基本步骤如下:

  • hotel-demo对外提供接口,用来修改elasticsearch中的数据

  • 酒店管理服务在完成数据库操作后,直接调用hotel-demo提供的接口,

方案二:异步通知  

流程如下:

  • hotel-admin对mysql数据库数据完成增、删、改后,发送MQ消息

  • hotel-demo监听MQ,接收到消息后完成elasticsearch数据修改

方案三:监听binlog  

流程如下:

  • 给mysql开启binlog功能

  • mysql完成增、删、改操作都会记录在binlog中

  • hotel-demo基于canal监听binlog变化,实时更新elasticsearch中的内容

小结:

方式一:同步调用

  • 优点:实现简单,粗暴

  • 缺点:业务耦合度高

方式二:异步通知

  • 优点:低耦合,实现难度一般

  • 缺点:依赖mq的可靠性

方式三:监听binlog

  • 优点:完全解除服务间耦合

  • 缺点:开启binlog增加数据库负担、实现复杂度高