前言

本文旨在介绍Elasticsearch,包括:

如果你有如下疑问:

那这篇文章肯定能帮助到你。

ES数据类型

string

string分两种,textkeyword

text类型储存,当我们不去特殊定义它的分词器,那么ES就会使用默认的分词器standard

image.png

而ES搜索的时候搜的是倒排索引,也就是分词后的字符串,这就意味着,如果使用text类型去储存你本不想分词的string类型,你在查询的时候,查询结果将违背你的预期:

image.png

其中term查询本应该是精准匹配,按理说能查到完整字符串,但因为field1是text类型,所以搜索不到。这时如果搜索单独的分词比如“数”,是可以搜到的。

要想ES不分词,就要使用keyword类型:

image.png

小结:text分词,keyword不分词。

date

ES的date类型允许我们规定格式,可以使用的格式有:

一旦我们规定了格式,如果新增数据不符合这个格式,ES将会报错mapper_parsing_exception。

复杂类型

ES有3个复杂类型:Array、object、nested。

Array:在Elasticsearch中,数组不需要专用的字段数据类型。默认情况下,任何字段都可以包含零个或多个值,但是,数组中的所有值都必须具有相同的数据类型。

image.png

Object:这个要注意object类型的字段,也可以有多个值,形成List<object>的数据结构,而且object不允许彼此独立地索引查询

image.png

可以看到本来我们只想查name是cg,age是1的数据,但是搜出了两个,这就是因为object不允许彼此独立地索引查询;要想objcet能被独立索引,就需要netest类型。

Nested类型:需要建立对象数组的索引并保持数组中每个对象的独立性,则应使用nested数据类型而不是object数据类型。在内部,每个嵌套的对象可以被独立的查询。

Geo地理位置

image.png

Geo-point的格式有好几种,查询时可以按照距离查附近的数据,具体可以看看官方文档。

倒排索引

上回书提到了倒排索引,它是ES能快速查找的根基,这回就讲讲什么是倒排索引。

假如有个博客系统,如果用MySQl的话大概会这么存储:

Id Author Title Content
1 cg Es hands on 学习ES
2 cg Mysql hands on 快乐学习MySQL

这样用Id或者Title是可以快速查找到相应的博客,因为Id、Title是很方便建立索引的。但当搜索Content却不能高效查询,因为Content是没法建立索引的。倒排索引就是把Content分词,然后用分词快速查询Id来建立索引:

Token id=1 id = 2
学习 T T
快乐 F T
ES T F
MySQL F T

倒排序索引包含两个部分:

倒排索引项:

比如以Token“学习”为例:

Token doc_Id TF Position Offset
学习 1 1 0 <0,2>
  2 1 1 <2,4>

搜索的过程:

可以看到匹配不匹配的到和分词有很大的关系,在ES中是通过Analyzer来分词的。

Analyzer由三部分组成:

自定义Analyzer

image.png

要先close再open才能操作settings里的analyzer

Full text queries

ik分词

一般情况下,为了提高搜索的效果,需要这两种分词器配合使用。既建索引时用 ik_max_word 尽可能多的分词,而搜索时用 ik_smart 尽可能提高匹配准度,让用户的搜索尽可能的准确。比如一个常见的场景,就是搜索”进口红酒”的时候,尽可能的不要出现口红相关商品或者让口红不要排在前面。

Full text queries – match

先建个新字段:

image.png

注意这个字段本身是keyword类型,但又有两个text类型的子field,分别配置了不同的分词器,相比粗暴的用不同的字段去实现配置不同的分词器而言,一个字段配置多个分词器在数据的存储和操作上方便许多,只用储存一个字段,即可得到不同的分词效果。

填充一点数据:

image.png

对content默认的keyword进行检索:

image.png

原因之前也说过,很简单,因为keyword是不会分词的。

对content做了分词的子字段进行检索:

image.png

ik_smart会把“真有意思”分成一个词,所以第二个查询只能查到前两个文档。

指定operator参数:

image.png

还行,有意思被分词为还行有意思两个token;不指定operator的话默认是or,所以10和11能被搜到;

指定成and的话则需要文档同时包含这两个token,所以没有结果。

Full text queries – match_phrase

match_phrase

match_phrase 会将检索关键词分词。match_phrase的分词结果必须在被检索字段的分词中都包含,而且顺序必须相同,而且默认必须都是连续的。

image.png

slop参数

image.png

slop参数表示token之间的位置距离容差值,上面是1表示token之前可以跳一个token,所以上面可以检索出10和11。

Full text queries – match_phrase_prefix

与match_phrase查询类似,但是会对最后一个Token在倒排序索引列表中进行通配符搜索。Token的模糊匹配数控制:max_expansions默认值为50;

image.png

因为ik_smart会把文档12中的真有意思分成一个词,所以只能检索到10和11。


到此,我们已经学习了 Full text queries最常用的3种查询:


Full text queries – multi_match

multi_match就是match的多字段版本,需要注意的是,多个fields之间的查询关系是or

image.png

字段^数字:表示增强该字段(权重影响相关性评分):

image.png

Full text queries – query_string

允许我们在单个查询字符串中指定AND | OR | NOT条件,同时也和multi_match一样,支持多字段搜索。

image.png

Full text queries – simple_query_string

类似于query_string ,但是会忽略错误的语法,永远不会引发异常,并且会丢弃查询的无效部分。

simple_query_string支持以下特殊字符:

image.png

Term level Queries

Term level queries - term

Term查询和Match区别在于Term不会对被检索的字段分词;Term一般用于检索不会被分词的字段,主要是类型为:integer、keyword、boolean 的字段。

image.png

Term level queries - terms

相当于MySQL的in:

image.png

terms lookup

image.png

相当于select * from tags_index where id in (select tag from blogs_index where id = 3)

Term level queries - wildcard

类似MySQL的like,为了防止极慢的通配符查询,通配符术语不应以通配符*?开头。

image.png

Term level queries - prefix

image.png

和上面wildcardc*等价。

Term level queries - fuzzy

模糊查询使用基于Levenshtein编辑距离的相似度。是一种误拼写时的fuzzy模糊搜索技术,用于搜索的时候可能输入的文本会出现误拼写的情况。比如输入”hands”,这时候也要匹配到“hansd”

image.png

如果prefix_length将设置为0,并且max_expansions将设置为很高的数字,则此查询可能会很繁琐。这可能会导致索引中的每一项都受到检查!

Term level queries - exists

image.png

image.png

Term level queries - terms_set

terms_setterms差不多,但是可以指定要匹配的数量:

image.png

如果每个文档需要的required_matches值都相同时,那就没必要用这个里,直接用match就行:

image.png

Term level queries - regexp query

image.png

注意:regexp查询的性能在很大程度上取决于所选的正则表达式。.*都很慢,而且使用环视正则表达式也很慢。如果可以的话,应在正则表达式开始之前尝试使用长前缀 .

Bool Query

Bool Query把其它的Query都组合了起来,可以说是最重要的查询了。

在讲Bool Query之前,ES有个关键的东西一直没讲,那就是Query Context和Filter Context

ES中一个重要的概念就是得分,用ES不仅是因为它快,还因为ES能做到MySQL做不到的 – 返回匹配程度,搜的结果有一个得分,得分越高,就表示文档越匹配;那就有个问题,有的查询需要看得分,有的不一定需要,这就区分除了两种查询:

Bool Query是由而且仅由下面一个或多个字句构建的:

其它注意事项:

比如:

image.png

should比较特殊,有些情况下它只影响得分,有些情况下则需要匹配:

当bool查询只包含should,则文档必须至少满足一个条件

image.png

表示field2的tokens 包含 'ok' & (field1的tokens 包含 'elephant' or 'field1的tokens 包含 'cat')

当bool查询同时也包含了must或者filter,文档不必满足should条件,但是如果满足条件,会增加相关性得分

image.png

表示field2的tokens 包含 'ok'、如果(field1的tokens 包含 'elephant'则得分更高。

当配置了minimum_should_match,则文档必须满足配置的条件个数或者百分比;

Aggregations

ES的聚合一共有4种类型

image.png

aggregations的语法结构:【注意aggregations关键字可使用aggs代替】

image.png

应用

最开始引入CSS是为了解决列表慢、超时的情况:

这种慢、超时的问题其实是典型问题:

于是构建了通用的CSS方案,:

能解决大部分因为数据库查询慢而引发的慢接口问题。