ElasticSearch

一、概念

1、倒排索引

①常规查询

根据id查询数据

②倒排索引

[1]原始数据分词
文档 ID文档内容
1谷歌地图之父跳槽Facebook
2谷歌地图之父加盟Facebook
3谷歌地图创始人拉斯离开谷歌加盟Facebook
4谷歌地图之父跳槽Facebook,与Wave项目取消有关
5谷歌地图之父拉斯加盟社交网站Facebook
文档 ID文档内容
1[谷歌] [地图] [之父] [跳槽] [Facebook]
2[谷歌] [地图] [之父] [加盟] [Facebook]
3[谷歌] [地图] [创始] [创始人] [拉斯] [离开] [加盟] [Facebook]
4[谷歌] [地图] [之父] [跳槽] [Facebook] [与] [Wave] [项目] [取消] [有关]
5[谷歌] [地图] [之父] [拉斯] [加盟] [社交] [网站] [Facebook]
[2]建立索引
单词 ID单词关联文档的 ID
1谷歌1 2 3 4 5
2地图1 2 3 4 5
3之父1 2 4 5
4跳槽1 4
5Facebook1 2 3 4 5
6加盟2 3 5
7创始3
8创始人3
9拉斯3 5
10离开3
114
12Wave4
13项目4
14取消4
15有关4
16社交5
17网站5
[3]搜索

用户搜索关键词:拉斯

到索引记录中查询,得知“拉斯”这个词曾出现在id为3和id为5的文档中。

然后就可以根据3和5查询文档本身的数据。

由于这里我们是根据关键词(或关键词分词结果)到索引表中查询得到id,这一步和传统查询根据id查询数据相反,所以叫倒排索引。

ElasticSearch中的索引和MySQL中的索引有啥异同?
相同点:思路一样,都是借助索引提高查询速度。
不同点:ElasticSearch的索引基于分词,是倒排索引结构;MySQL索引是B+Tree结构。

2、数据结构

ElasticSearchMySQL
index数据库
mapping表结构
type
document记录/行
field字段/列

ElasticSearch较高的版本已经废除了type这个概念。

3、数据类型

①是否分词

ElasticSearch中字符串类型有两种情况:

  • text:分词
  • keyword:不分词

衡量标准:分词之后,分词的结果是否有意义。

例如:深圳,树,/group1/M00/00/02/wKjIgGN8rueEPlm6AAAAACY3A9Q664.png

②是否建立索引

在org.springframework.data.elasticsearch.annotations.Field注解中,通过index属性设置:

  • true:建立索引。大部分常规数据,只要是有可能填写到搜索框中的,都建立索引
  • false:不建立索引,意思是不根据这个字段建立索引。例如:图片地址

③是否存储

在org.springframework.data.elasticsearch.annotations.Field注解中,通过store属性设置:

  • true:存储
  • false:不存储

是否存储是指:该字段是否在 _source 之外再做一个额外的存储。这样对于做了存储的字段可以通过 stored_fields 方式获取。
这一点我们作为初学者不必深究,我们只需要知道:即使我们设置了 store 为 false,查询结果中 _source 这里也仍然能够显示该字段。
所以通常是没有影响的。

二、基本操作

1、连接Kibana

友情提示:Kibana在虚拟机启动后,需要等比较长的时间(几分钟)才能访问。

2、基本操作

  • index增删改查
  • mapping增删改查
  • document增删改查

三、DSL语句

1、query关键词语法结构

请添加图片描述

2、测试数据

  • 测试数据
POST db_song/_doc
{
  "song_name":"give me an apple",
  "song_singer":"tom",
  "song_album":"apple pie",
  "song_lyrics":"i want to give you an apple",
  "song_price":10
}

POST db_song/_doc
{
  "song_name":"happy tears",
  "song_singer":"jerry",
  "song_album":"apple farmer",
  "song_lyrics":"i will go to London",
  "song_price":20
}

POST db_song/_doc
{
  "song_name":"tears of happy",
  "song_singer":"jerry",
  "song_album":"apple farmer",
  "song_lyrics":"i will go to NewYork",
  "song_price":30
}

POST db_song/_doc
{
  "song_name":"fly me",
  "song_singer":"bigger one",
  "song_album":"two star",
  "song_lyrics":"i put an apple on your table",
  "song_price":40
}

3、常规查询

①term

特点:关键词不分词。

举例:关键词是happy tears

搜索结果:未命中,搜索结果列表为空

GET db_song/_search
{
  "query": {
    "term": {
      "song_name": {
        "value": "happy tears"
      }
    }
  }
}

说明:happy tears被作为一个整体,和“happy”、“tears”都不匹配,所以没有搜索结果。

②match

特点:关键词分词

举例:关键词是happy tears

搜索结果:匹配到两条记录

GET db_song/_search
{
  "query": {
    "match": {
      "song_name": "happy tears"
    }
  }
}

③multi_match

特点:关键词分词而且可以匹配多个字段

举例:搜索结果匹配到4条记录

GET db_song/_search
{
  "query": {
    "multi_match": {
      "query": "happy apple",
      "fields": [
        "song_name",
        "song_album",
        "song_lyrics"
      ]
    }
  }
}

④bool查询

bool 查询有四种子句可以选用,分别是:

  • must:指定多个必须满足的条件,各个条件之间是且的关系
    • A条件 and B条件
  • must_not:指定多个必须不满足的条件
    • !A条件 and !B条件
  • should:指定多个条件,各个条件之间是或的关系
    • A条件 or B条件
  • filter:根据指定的条件进行过滤

而上面所提到的条件也就是前面我们刚刚学过的 term、terms、match、match_all、multi_match、match_phrase、range。也就是说:bool 查询就是通过 must、must_not、should、filter 这四个关键词把前面的基本查询方式进一步整合起来,实现更复杂的查询条件。

这很像 SQL 中使用 AND、OR 把 LIKE、BETWEEN AND、IN、NOT IN 等查询条件组合起来。

举例:

GET db_song/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "song_name": "happy"
          }
        },
        {
          "match": {
            "song_album": "apple"
          }
        }
      ],
      "filter": {
        "range": {
          "song_price": {
            "gte": 10,
            "lte": 20
          }
        }
      }
    }
  }
}

友情提示:
DSL语句往往能够用很多不同写法完成同样的功能。
所以我们对自己的要求就是:
●借助Kibana提示能够写常规的DSL语句,实现常规功能。
●别人写的DSL语句大致看懂。

⑤聚合查询

[1]概念

聚合查询其实就是分组,相当于SQL语句中的group by。

下面介绍ElasticSearch中关于聚合的两个概念:

  • 桶(Bucket):其实就是分组以后的“组”
  • 度量(metrics):其实就是SQL语句中的聚合函数
度量方式说明
Avg Aggregation求平均值
Max Aggregation求最大值
Min Aggregation求最小值
Percentiles Aggregation求百分比
Stats Aggregation同时返回avg、max、min、sum、count等
Sum Aggregation求和
Top hits Aggregation求前几
Value Count Aggregation求总数

注意:划分桶时所依据的 filed 不能分词!所以一定要使用 keyword 类型。

[2]操作举例

请添加图片描述

[3]集合数据类型的聚合

前面我们举例说明的是针对多个document进行聚合(分组)。

此时还有一种特殊情况:某一个字段是集合类型的时候,我们针对这个集合数据进行聚合(分组)操作。

集合数据作为一种比较特殊的类型,在ElasticSearch中类型的名称是:nested

在DSL语句中表现形式是JSON数组的格式。

[4]并列聚合

并列的聚合操作,各自执行各自的聚合逻辑,互不干扰

GET goods/_search
{
  "aggs": {
    "agg_tm_name_me": {
      "terms": {
        "field": "tmName",
        "size": 10
      }
    },
    "agg_tm_id_me": {
      "terms": {
        "field": "tmId",
        "size": 10
      }
    },
    "agg_cate_3_name_me": {
      "terms": {
        "field": "category3Name",
        "size": 10
      }
    }
  }
}
[5]嵌套聚合

嵌套聚合就是在组内再分组

GET goods/_search
{
  "aggs": {
    "agg_tm_name_me": {
      "terms": {
        "field": "tmName",
        "size": 10
      },
      "aggs": {
        "agg_tm_id_me": {
          "terms": {
            "field": "tmId",
            "size": 10
          }
        }
      }
    }
  }
}

4、nested数据类型

①提出问题

先执行下列DSL语句创建测试用的index

PUT my_index/_doc/1
{
  "group": "fans",
  "user": [
    {
      "first": "John",
      "last": "Smith"
    },
    {
      "first": "Alice",
      "last": "White"
    }
  ]
}

然后执行查询

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "user.first": "Alice"
          }
        },
        {
          "match": {
            "user.last": "Smith"
          }
        }
      ]
    }
  }
}

查询结果分析:

  • 本来must关键字表示“且”的关系,从逻辑上来讲,当前查询条件不应该有查询结果。
  • 但是查询结果却查到了
    请添加图片描述

原因是创建my_index的时候,它的默认数据类型是Object。数据在底层存储方式如下:

{"user.first":"John,Alice"}
{"user.last":"Smith,White"}

但实际上我们创建这一数据结构的本意是:

  • User1:John Smith
  • User2:Alice White

而查询条件中的Alice Smith按照我们的本意来说,不应该存在。

此时对照我们的查询条件,在user.first中匹配到了Alice,在user.last中匹配到了Smith,所以这两个条件都满足。

所以当前document就出现了在了查询结果中。

②修改数据结构

重新创建index

# 删除上面例子中旧的 my_index
DELETE /my_index

# 创建新 my_index 同时指定 mapping
# first 和 last 设置为 keyword 是为了后面测试聚合
PUT my_index
{
  "mappings": {
    "_doc": {
      "properties": {
        "user": {
          "type": "nested",
          "properties": {
            "first": {
              "type": "keyword"
            },
            "last": {
              "type": "keyword"
            }
          }
        }
      }
    }
  }
}

重新存入数据(这一步和前面是一样的)

PUT my_index/_doc/1
{
  "group": "fans",
  "user": [
    {
      "first": "John",
      "last": "Smith"
    },
    {
      "first": "Alice",
      "last": "White"
    }
  ]
}

③重新查询

此时查询user这个字段,因为它是netsted类型,所以query关键词下面又指定了netsted关键词;path关键词指定了具体要查询的字段:

GET /my_index/_search
{
  "query": {
    "nested": {
      "path": "user",
      "query": {
        "bool": {
          "must": [
            {"match": {"user.first": "Alice"}},
            {"match": {"user.last": "Smith"}}
          ]
        }
      }
    }
  }
}

请添加图片描述

下面语句是能够查询到结果的:

GET /my_index/_search
{
  "query": {
    "nested": {
      "path": "user",
      "query": {
        "bool": {
          "must": [
            {"match": {"user.first": "Alice"}},
            {"match": {"user.last": "White"}}
          ]
        }
      }
    }
  }
}

查询结果如下:
请添加图片描述

说明:上面查询结果会包含John Smith数据,这并不是因为John Smith匹配查询条件,它出现是因为整个document符合查询条件,所以显示了整个document。

④聚合语法

在针对nested类型的字段进行聚合操作时,aggs下的语法也不一样了:

  • 聚合方式要选择nested
  • 通过path指定聚合字段
  • 和nested同级需要再写一个aggs,这里就针对nested类型的数据的某个字段聚合
GET my_index/_search
{
  "aggs": {
    "fan": {
      "nested": {
        "path": "user"
      },
      "aggs": {
        "agg_fan": {
          "terms": {
            "field": "user.first"
          }
        }
      }
    }
  }
}

执行结果:

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小张不嚣张@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值