念念不忘 必有回响

你若盛开,清风自来


  • 首页

  • 分类

  • 归档

  • 标签

  • 关于

  • 搜索

【MySQL 原理】02 索引原理与实现(一)

发表于 2019-05-14 | 更新于 2019-05-22 | 分类于 MySQL , 原理分析 | 评论数:

前言

讲到索引,第一反应肯定是能提高查询效率。例如书的目录,想要查找某一章节,会先从目录中定位。如果没有目录,那么就需要将所有内容都看一遍才能找到。

索引的设计对程序的性能至关重要,若索引太少,对查询性能受影响;而如果索引太多,则会影响增/改/删等的性能。

知识点

MySQL中一般支持以下几种常见的索引:

  • B+树索引
  • 全文索引
  • 哈希索引

我们今天重点来讲下B+树索引,以及为什么要用B+树来作为索引的数据结构。

B+树索引并不能直接找到具体的行,只是找到被查找行所在的页,然后DB通过把整页读入内存,再在内存中查找。

重温数据结构

1.1 哈希结构

如有 3、1、2、10、9、0、4、6这8个数据,建立如图1-1所示哈希索引。

  • 直接查询:现在要从8个数中查找6这条记录,只需要计算6的哈希值,便可快速定位记录,时间复杂度为O(1)。

  • 范围查询:如果要进行范围查询(大于4的数据),那这个索引就完全没用了。


图1-1 哈希索引

1.2 二叉树查找树

二叉树是一种经典的数据结构,要求左子树小于根节点,右子树大于根节点。

如有 3、1、2、10、9、0、4、6这8个数据,建立如图1-2所示二分查找树。

  • 直接查询:假设查找键值为6的记录,先找到根4,4<6,因此查找4的右子树,找到9;9大于6,因此查找9的左子树;一共查找3次。但如果顺序查找,则需要查找8次(位于最后)。

  • 范围查询:如果需要查找大于4的数据,则遍历4的右子树就行了。


图1-2 二叉查找树

1.3 平衡二叉树(AVL树)

按照二叉查找树的定义,它是可以任意的构造,同样是这些数字,可以按照图1-3-1的方式来建立二叉查找树。同样查找数据6,需要查找5次。


图1-3-1 性能较差的二叉查找树

因此为了最大性能地构造一个二叉查找树,需要它是平衡的,即平衡二叉树。

平衡二叉树定义:首先符合二叉查找树的定义,另外任何节点的两个子树高度最大差为1。

平衡二叉树的查询速度是很快的,但是有缺点:

  1. 维护树的代价是非常大,在进行插入或更新时,经常会需要多次左旋或右旋来维持平衡。如图1-3-2所示
  2. 数据量多的时候,树会很高,需要多次I/O操作。
  3. 在进行范围查找时,假设查找>=3,先找到3,然后需要查找到3的父节点,然后遍历父节点的右子树。

May-22-2019 14-27-44的副本
图1-3-2 平衡二叉树AVL

1.4 B+ 树

在B+树中,所有记录节点存放在叶子节点上,且是顺序存放,由各叶子节点指针进行连接。如果从最左边的叶子节点开始顺序遍历,能得到所有键值的顺序排序。

如有 3、1、2、10、9、0、4、6这8个数据,可建立如图1-4-1所示高度为2的B+树。


图1-4-1 高度为2的B+树

在进行更新时,B+树同样需要类似二叉树的旋转操作。举例,假设新增一个7,那可以直接填充到4、6的后面。如果再添加8,那么就需要进行旋转了,感受下面的B+树旋转过程。


图1-4-2 高度为3的B+树

采用B+树的索引结构优点:

  1. B+树的高度一般为2-4层,所以查找记录时最多只需要2-4次IO,相对二叉平衡树已经大大降低了。
  2. 范围查找时,能通过叶子节点的指针获取数据。例如查找大于等于3的数据,当在叶子节点中查到3时,通过3的尾指针便能获取所有数据,而不需要再像二叉树一样再获取到3的父节点。

看到这应该明白mysql索引为什么使用B+树了吧!!!

未完待续…

【Golang进阶】flag 命令行包使用

发表于 2019-05-06 | 分类于 Golang , 进阶 | 评论数:

Package flag

import “flag”

flag 包实现命令行标签解析.

简单Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"flag"
"fmt"
)

var num = flag.Int("num", 1234, "Input your ip")
var config = flag.String("config", "default.conf", "Input your config file path")

func main() {
flag.Parse()
fmt.Println("ip has value ", *num)
fmt.Println("config file path ", *config)
}

像Linux命令行一样查看帮助

执行时不带参数,使用默认值

执行时赋值参数

使用说明:

  1. 定义标签
1
2
3
4
5
6
7
8
9
10
11
// 定义interger标签
var num = flag.Int("num", 1234, "Input your ip")

// 定义string标签
var config = flag.String("config", "default.conf", "Input your config file path")

// Var()函数将标签绑定到指定变量中
var flagvar int
func InitFlag() {
flag.IntVar(&flagvar, "flagvar", 1234, "Input your flagvar name")
}
  1. 解析参数
1
flag.Parse()
  1. 使用标签
1
2
fmt.Println("ip has value ", *num)
fmt.Println("config file path ", *config)

经验

在开发的时候,很多时候会有多个环境,基本会以这种方式去加载对应环境的配置文件

参考:

https://godoc.org/flag

Gopher China 2016

发表于 2019-05-04 | 更新于 2019-05-05 | 分类于 Golang , Gopher | 评论数:

Why Go

gofmt 团队代码风格一致
强类型语言,任何严肃的项目都不应该用弱类型语言
import 很好的开源协同开发
profile 能力强大
build standalone binary 简单部署
goroutines 提供天然的并发编程
微服务最好的语言:native web框架、gRPC、docker

GC 优化思路

Mark and Sweep: 大量时间用于扫描对象

常规手段的核心:减少对象

Gopher China 大会视频

发表于 2019-05-04 | 更新于 2019-05-05 | 分类于 Golang , Gopher | 评论数:

https://segmentfault.com/a/1190000018560530

【Golang零基础入门】06 Goroutine

发表于 2019-04-20 | 更新于 2019-05-20 | 分类于 Golang , 零基础入门 | 评论数:

引言

现在很多一线大厂都转型到Go,究其原因就是该语言对并发支持的好。
相信大家都知道Golang是在语言级原生支持协程,先看看下面这段代码

1
2
3
4
5
6
7
8
9
10
11
func main()  {
for i:=0; i<10; i++ {
go func(i int) {
for {
fmt.Printf("协程: %d \n", i)
}
}(i)
}
// 防止程序来不及打印就退出
time.Sleep(10*time.Microsecond)
}

输出结果如下,你会发现每次运行,输出内容都是不一样的,这是为什么呢?

一、并行与并发

并行是指程序的运行状态,要有两个线程正在执行才能算是Parallelism;

并发指程序的逻辑结构,Concurrency则只要有两个以上线程还在执行过程中即可。

简单地说,Parallelism要在多核或者多处理器情况下才能做到,而Concurrency则不需要。
对应后面的runtime.GOMAXPROCS(runtime.NumCPU())

二、进程,线程与协程

goroutines是Go的并发基础,为了帮助我们理解这个概念,我们先来谈一谈并发的发展故事。

2.1 进程 Process

进程是程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是线程的容器。

在分时系统中,操作系统通过记录当前进程的状态,然后恢复另一个进程的状态,在活动进程之间快速切换CPU的处理,而产生了一种并发执行的错觉,这个过程称为上下文切换(switch cost)。

上下文切换的成本是:

  • 内核需要存储该进程的所有CPU寄存器的内容,然后恢复另一个进程的值。由于进程切换可以在进程执行的任何时刻发生,操作系统需要存储所有这些寄存器的内容,因为它不知道当前正在使用哪些寄存器。
  • 内核需要将CPU的虚拟地址刷新为物理地址映射(TLB缓存)。
  • 操作系统上下文切换的开销,以及选择下一个进程都会占用CPU的调度程序函数的开销。

2.2 线程 thread

线程是操作系统能够进行运算调度的最小单位,在概念上与进程类似,但共享相同的内存空间。由于线程共享地址空间,因此创建、切换速度更快。但仍然有昂贵的上下文切换成本; 必须保留很多状态。

2.3 协程 Coroutine

协程是用户态线程,不依靠内核来管理调度,具备以下特点:

  • 轻量级线程
  • 非抢占式多任务处理,由协程自己本省主动交出控制权

以下列出了goroutine之间切换的主要的时间点:

(1)Channel发送和接收操作(如果这些操作是阻塞的);
(2)执行go语句,虽然不能保证新的goroutine马上被调度执行;
(3)阻塞的系统调用,像文件操作,网络操作,IO等等;
(4)停下来进入垃圾回收周期以后。

换句话讲,在goroutine不能继续进行运算以后(需要更多数据,更多空间,等等),都会进行切换。


双向通道就是channel

GO的协程 Goroutines

每个并发的执行单元叫做goroutine,用关键词go来创建。
具体goroutine放在哪个线程,由调度器控制与切换。

假设要计算两个非常复杂的逻辑,然后输出结果。在正常是线性程序里面,会依次调用计算的逻辑,完成之后再调用输出逻辑。但如果是在有两个甚至更多个goroutine的程序中,对两个计算逻辑的调用就可以在同一时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func main() {
var wg sync.WaitGroup
wg.Add(2)
go func() {
for i:=0; i<100; i++ {
defer wg.Done()
fmt.Println("A:", i)
time.Sleep(1*time.Second)
}
}()

go func() {
for i:=0; i<100; i++ {
defer wg.Done()
fmt.Println("B:", i)
time.Sleep(2*time.Second)
}
}()
wg.Wait()
}

我们运行这个程序,会发现A和B前缀会交叉出现,即两个程序是并发在执行的,并且每次运行的结果可能不一样,这就是Go调度器调度的结果。

这里的sync.WaitGroup其实是一个计数的信号量,使用它的目的是要main函数等待两个goroutine执行完成后再结束,不然这两个goroutine还在运行的时候,程序就结束了,看不到想要的结果。

sync.WaitGroup的使用也非常简单,先是使用Add 方法设设置计算器为2,每一个goroutine的函数执行完之后,就调用Done方法减1。Wait方法的意思是如果计数器大于0,就会阻塞,所以main 函数会一直等待2个goroutine完成后,再结束。

对于逻辑处理器的个数,不是越多越好,要根据电脑的实际物理核数,如果不是多核的,设置再多的逻辑处理器个数也没用,如果需要设置的话,一般我们采用如下代码设置。

1
runtime.GOMAXPROCS(runtime.NumCPU())

所以对于并发来说,就是Go语言本身自己实现的调度,对于并行来说,是和运行的电脑的物理处理器的核数有关的,多核就可以并行并发,单核只能并发了。

Elastic Search 分布式特性

发表于 2019-04-12 | 分类于 ElasticSearch | 评论数:

当索引一个文档的时候,文档会被存储到一个主分片中。

路由公式:

shard = hash(routing) % number_of_primary_shards

主分片和副分片交互

可以发送请求到集群中的任一节点。 每个节点都有能力处理任意请求。 每个节点都知道集群中任一文档位置,所以可以直接将请求转发到需要的节点上。

当发送请求的时候, 为了扩展负载,更好的做法是轮询集群中所有的节点。

新建、索引和删除单个文档

以下是在主副分片和任何副本分片上面 成功新建,索引和删除文档所需要的步骤顺序:

客户端向 Node 1 发送新建、索引或者删除请求。
节点使用文档的 _id 确定文档属于分片 0 。请求会被转发到 Node 3,因为分片 0 的主分片目前被分配在Node 3 上。
Node 3 在主分片上面执行请求。如果成功了,它将请求并行转发到 Node 1 和 Node 2 的副本分片上。一旦所有的副本分片都报告成功, Node 3 将向协调节点报告成功,协调节点向客户端报告成功。

读取文档

以下是从主分片或者副本分片检索文档的步骤顺序:

1、客户端向 Node 1 发送获取请求。

2、节点使用文档的 _id 来确定文档属于分片 0 。分片 0 的副本分片存在于所有的三个节点上。 在这种情况下,它将请求转发到 Node 2 。

3、Node 2 将文档返回给 Node 1 ,然后将文档返回给客户端。

在处理读取请求时,协调结点在每次请求的时候都会通过轮询所有的副本分片来达到负载均衡。

mget读取多个文档

以下是使用单个 mget 请求取回多个文档所需的步骤顺序:
客户端向 Node 1 发送 mget 请求。
Node 1 为每个分片构建多文档获取请求,然后并行转发这些请求到托管在每个所需的主分片或者副本分片的节点上。一旦收到所有答复, Node 1 构建响应并将其返回给客户端。

使用 bulk 修改多个文档

bulk API 按如下步骤顺序执行:

客户端向 Node 1 发送 bulk 请求。
Node 1 为每个节点创建一个批量请求,并将这些请求并行转发到每个包含主分片的节点主机。
主分片一个接一个按顺序执行每个操作。当每个操作成功时,主分片并行转发新文档(或删除)到副本分片,然后执行下一个操作。 一旦所有的副本分片报告所有操作成功,该节点将向协调节点报告成功,协调节点将这些响应收集整理并返回给客户端。
bulk API 还可以在整个批量请求的最顶层使用 consistency 参数,以及在每个请求中的元数据中使用 routing 参数。

Elastic Search 分布式特性

发表于 2019-04-11 | 更新于 2019-04-12 | 分类于 ElasticSearch | 评论数:

在 Elasticsearch 中, 每个字段的所有数据 都是 默认被索引的 。 即每个字段都有为了快速检索设置的专用倒排索引。而且,不像其他多数的数据库,它能在 同一个查询中 使用所有这些倒排索引,并以惊人的速度返回结果。

文档

一个对象仅仅是类似于 hash 、 hashmap 、字典或者关联数组的 JSON 对象,对象中也可以嵌套其他的对象。 对象可能包含了另外一些对象。

在 Elasticsearch 中,术语 文档 有着特定的含义。它是指最顶层或者根对象, 这个根对象被序列化成 JSON 并存储到 Elasticsearch 中,指定了唯一 ID。

文档元数据
_index:一个 索引 应该是因共同的特性被分组到一起的文档集合。类比数据库
_type:在索引中对数据进行逻辑分区。类比数据表
_id:当它和 _index 以及 _type 组合就可以唯一确定 Elasticsearch 中的一个文档。类比数据唯一标识

写数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
PUT /{index}/{type}/{id}
{
"field": "value",
...
}

# For Example

curl -X PUT "10.96.83.188:9200/website/blog/123" -H 'Content-Type: application/json' -d'
{
"title": "My first blog entry",
"text": "Just trying this out...",
"date": "2014/01/01"
}
'
{"_index":"website","_type":"blog","_id":"123","_version":1,"result":"created",
"_shards":{"total":2,"successful":1,"failed":0},"created":true}

# 如果没有指定ID,Elasticsearch 可以帮我们自动生成 ID
curl -X POST "10.96.83.188:9200/website/blog/" -H 'Content-Type: application/json' -d'
{
"title": "My second blog entry",
"text": "Still trying this out...",
"date": "2014/01/01"
}
'
{"_index":"website","_type":"blog","_id":"AWoPmj2eBvBN4YG5RXks","_version":1,
"result":"created","_shards":{"total":2,"successful":1,"failed":0},"created":true}

读数据
pretty 为了让输出更友好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#取所有字段
curl -X GET "10.96.83.188:9200/website/blog/123?pretty"
{
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 1,
"found" : true,
"_source" : {
"title" : "My first blog entry",
"text" : "Just trying this out...",
"date" : "2014/01/01"
}
}

# 取部分字段
curl -X GET "10.96.83.188:9200/website/blog/123?_source=title,text&pretty"
{
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 1,
"found" : true,
"_source" : {
"text" : "Just trying this out...",
"title" : "My first blog entry"
}
}

# 只取数据,不去元数据
curl -X GET "10.96.83.188:9200/website/blog/123/_source"

{
"title": "My first blog entry",
"text": "Just trying this out...",
"date": "2014/01/01"
}

# 读取多个数据
curl -X GET "10.96.83.188:9200/_mget?pretty" -H 'Content-Type: application/json' -d'
{
"docs" : [
{
"_index" : "website",
"_type" : "blog",
"_id" : 1
},
{
"_index" : "website",
"_type" : "blog",
"_id" : 124
}
]
}
'

判断文档是否存在(200存在,404不存在)

1
2
3
4
5
6
7
8
9
$ curl -I -XHEAD "10.96.83.188:9200/website/blog/123/"
HTTP/1.1 200 OK
content-type: text/plain; charset=UTF-8
content-length: 0

$ curl -I -XHEAD "10.96.83.188:9200/website/blog/124/"
HTTP/1.1 404 Not Found
content-type: text/plain; charset=UTF-8
content-length: 0

更新操作

创建新文档

要么id保证唯一,要么不带id新建,由ES自动创建
创建时,带上_create,保证只新增,如果已存在则报错

1
2
3
4
5
6
7
8
9
curl -X PUT "10.96.83.188:9200/website/blog/123/_create" -H 'Content-Type: application/json' -d'
{
"title": "My first blog entry",
"text": "I am starting to get the hang of this...",
"date": "2014/01/02"
}
'

{"error":{"root_cause":[{"type":"version_conflict_engine_exception","reason":"[blog][123]: version conflict, document already exists (current version [2])","index_uuid":"_sBTT-DdSnKytaOhbXEYfw","shard":"0","index":"website"}],"type":"version_conflict_engine_exception","reason":"[blog][123]: version conflict, document already exists (current version [2])","index_uuid":"_sBTT-DdSnKytaOhbXEYfw","shard":"0","index":"website"},"status":409}

删除文档

1
2
curl -X DELETE "10.96.83.188:9200/website/blog/123"
{"found":true,"_index":"website","_type":"blog","_id":"123","_version":3,"result":"deleted","_shards":{"total":2,"successful":1,"failed":0}}

更新部分文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
curl -X POST "10.96.83.188:9200/website/blog/1/_update" -H 'Content-Type: application/json' -d'
{
"doc" : {
"tags" : [ "testing" ],
"views": 0
}
}
'

curl -X GET "10.96.83.188:9200/website/blog/1?pretty"
{
"_index" : "website",
"_type" : "blog",
"_id" : "1",
"_version" : 3,
"found" : true,
"_source" : {
"title" : "My first blog entry",
"text" : "Starting to get the hang of this...",
"views" : 0,
"tags" : [
"testing"
]
}
}

乐观并发控制

Elastic Search 分布式特性

发表于 2019-04-11 | 更新于 2019-04-25 | 分类于 ElasticSearch | 评论数:

Elasticsearch 可以横向扩展至数百(甚至数千)的服务器节点,同时可以处理PB级数据。
Elasticsearch 天生就是分布式的,并且在设计时屏蔽了分布式的复杂性。
这里列举了一些在后台自动执行的操作:

  • 分配文档到不同的容器 或 分片 中,文档可以储存在一个或多个节点中
  • 按集群节点来均衡分配这些分片,从而对索引和搜索过程进行负载均衡
  • 复制每个分片以支持数据冗余,从而防止硬件故障导致的数据丢失
  • 将集群中任一节点的请求路由到存有相关数据的节点
  • 集群扩容时无缝整合新节点,重新分配分片以便从离群节点恢复

Elasticsearch 是利用分片将数据分发到集群内各处的。分片是数据的容器,文档保存在分片内,分片又被分配到集群内的各个节点里。 当你的集群规模扩大或者缩小时, Elasticsearch 会自动的在各节点中迁移分片,使得数据仍然均匀分布在集群里。

一个分片可以是 主 分片或者 副本 分片。 索引内任意一个文档都归属于一个主分片,所以主分片的数目决定着索引能够保存的最大数据量。

一个副本分片只是一个主分片的拷贝。 副本分片作为硬件故障时保护数据不丢失的冗余备份,并为搜索和返回文档等读操作提供服务。

扩容
主分片的数目在索引创建时 就已经确定了下来。实际上,这个数目定义了这个索引能够 存储 的最大数据量。
但是,读操作——搜索和返回数据——可以同时被主分片 或 副本分片所处理,所以当你拥有越多的副本分片时,也将拥有越高的吞吐量。

当然,如果只是在相同节点数目的集群上增加更多的副本分片并不能提高性能,因为每个分片从节点上获得的资源会变少。 你需要增加更多的硬件资源来提升吞吐量。

故障

关闭的节点是一个主节点。而集群必须拥有一个主节点来保证正常工作,所以发生的第一件事情就是选举一个新的主节点: Node 2 。
新的主节点立即将这些分片在 Node 2 和 Node 3 上对应的副本分片提升为主分片, 此时集群的状态将会为 yellow 。 这个提升主分片的过程是瞬间发生的,如同按下一个开关一般。

Elastic Search 基础介绍

发表于 2019-04-11 | 更新于 2019-04-25 | 分类于 ElasticSearch | 评论数:

ElasticSearch 是一个分布式、可扩展、实时的搜索与数据分析引擎。

功能介绍

  • 全文搜索
  • 结构化数据的实时统计
  • 数据分析
  • 复杂的语言处理
  • 地理位置和对象间关联关系

应用场景

  • Wikipedia 使用 Elasticsearch 提供带有高亮片段的全文搜索
  • Stack Overflow 将地理位置查询融入全文检索中去,并且使用 more-like-this 接口去查找相关的问题与答案
  • GitHub 使用 Elasticsearch 对1300亿行代码进行查询

特点

  • 一个分布式的实时文档存储,每个字段 可以被索引与搜索
  • 一个分布式实时分析搜索引擎
  • 能胜任上百个服务节点的扩展,并支持 PB 级别的结构化或者非结构化数据

操作

索引结构分析

路径 /megacorp/employee/1 包含了三部分的信息:

megacorp:索引名称,类似数据库
employee:类型名称,类似数据表
1:特定雇员的ID,类似表里的ID

写入

1
2
3
4
5
6
7
8
9
curl -X PUT "localhost:9200/megacorp/employee/1" -H 'Content-Type: application/json' -d'
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
'

查询

1
2
3
4
5
6
7
8
9
10
curl  'localhost:9200/megacorp/employee/1?pretty'
{"_index":"megacorp","_type":"employee","_id":"2","_version":1,"found":true,"_source":
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
}

搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
curl -X GET "10.96.83.188:9200/megacorp/employee/_search"
{"took":71,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":3,"max_score":1.0,"hits":[{"_index":"megacorp","_type":"employee","_id":"2","_score":1.0,"_source":
{
"first_name" : "Jane",
"last_name" : "Smith",
"age" : 32,
"about" : "I like to collect rock albums",
"interests": [ "music" ]
}
},{"_index":"megacorp","_type":"employee","_id":"1","_score":1.0,"_source":
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
},{"_index":"megacorp","_type":"employee","_id":"3","_score":1.0,"_source":
{
"first_name" : "Douglas",
"last_name" : "Fir",
"age" : 35,
"about": "I like to build cabinets",
"interests": [ "forestry" ]
}
}]}}

简单查询 query_string

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
curl -X GET "10.96.83.188:9200/megacorp/employee/_search?q=last_name:Smith"
{"took":31,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":2,"max_score":0.2876821,"hits":[{"_index":"megacorp","_type":"employee","_id":"2","_score":0.2876821,"_source":
{
"first_name" : "Jane",
"last_name" : "Smith",
"age" : 32,
"about" : "I like to collect rock albums",
"interests": [ "music" ]
}
},{"_index":"megacorp","_type":"employee","_id":"1","_score":0.2876821,"_source":
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
}]}}

查询表达式搜索 query

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
curl -X GET "10.96.83.188:9200/megacorp/employee/_search" -H 'Content-Type: application/json' -d'
{
"query" : {
"match" : {
"last_name" : "Smith"
}
}
}
'

{"took":9,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":2,"max_score":0.2876821,"hits":[{"_index":"megacorp","_type":"employee","_id":"2","_score":0.2876821,"_source":
{
"first_name" : "Jane",
"last_name" : "Smith",
"age" : 32,
"about" : "I like to collect rock albums",
"interests": [ "music" ]
}
},{"_index":"megacorp","_type":"employee","_id":"1","_score":0.2876821,"_source":
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
}]}}

更复杂的搜索 过滤器 filter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
curl -X GET "10.96.83.188:9200/megacorp/employee/_search" -H 'Content-Type: application/json' -d'
{
"query" : {
"bool": {
"must": {
"match" : {
"last_name" : "smith"
}
},
"filter": {
"range" : {
"age" : { "gt" : 30 }
}
}
}
}
}
'
{"took":15,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":1,"max_score":0.2876821,"hits":[{"_index":"megacorp","_type":"employee","_id":"2","_score":0.2876821,"_source":
{
"first_name" : "Jane",
"last_name" : "Smith",
"age" : 32,
"about" : "I like to collect rock albums",
"interests": [ "music" ]
}
}]}}

全文搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
curl -X GET "10.96.83.188:9200/megacorp/employee/_search" -H 'Content-Type: application/json' -d'
{
"query" : {
"match" : {
"about" : "rock climbing"
}
}
}
'
{"took":8,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":2,"max_score":0.53484553,"hits":[{"_index":"megacorp","_type":"employee","_id":"1","_score":0.53484553,"_source":
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
},{"_index":"megacorp","_type":"employee","_id":"2","_score":0.26742277,"_source":
{
"first_name" : "Jane",
"last_name" : "Smith",
"age" : 32,
"about" : "I like to collect rock albums",
"interests": [ "music" ]
}
}]}}

Elasticsearch 默认按照相关性得分排序,即每个文档跟查询的匹配程度。
第一个最高得分的结果很明显:John Smith 的 about 属性清楚地写着 “rock climbing”
Jane Smith也作为结果返回,原因是她的 about 属性里提到了 “rock” 。因为只有 “rock” 而没有 “climbing” ,所以她的相关性得分低于 John 的。

这是完全区别于传统关系型数据库的一个概念,数据库中的一条记录要么匹配要么不匹配。

短语搜索

想要精确匹配一系列单词或者短语。
匹配同时包含 “rock” 和 “climbing” ,并且 二者以短语 “rock climbing” 的形式紧挨着的雇员记录。
为此对 match 查询稍作调整,使用一个叫做 match_phrase 的查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 curl -X GET "10.96.83.188:9200/megacorp/employee/_search" -H 'Content-Type: application/json' -d'
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
}
}
'
{"took":13,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":1,"max_score":0.53484553,"hits":[{"_index":"megacorp","_type":"employee","_id":"1","_score":0.53484553,"_source":
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
}]}}

高亮搜索

返回结果与之前一样,与此同时结果中还多了一个叫做 highlight 的部分。这个部分包含了 about 属性匹配的文本片段,并以 HTML 标签 封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
curl -X GET "10.96.83.188:9200/megacorp/employee/_search" -H 'Content-Type: application/json' -d'
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
},
"highlight": {
"fields" : {
"about" : {}
}
}
}
'
{"took":36,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":1,"max_score":0.53484553,"hits":[{"_index":"megacorp","_type":"employee","_id":"1","_score":0.53484553,"_source":
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
,"highlight":{"about":["I love to go <em>rock</em> <em>climbing</em>"]}}]}}

分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
curl -X GET "10.96.83.188:9200/megacorp/employee/_search" -H 'Content-Type: application/json' -d'
{
"aggs": {
"all_interests": {
"terms": { "field": "interests" }
}
}
}
'


{
...
"hits": { ... },
"aggregations": {
"all_interests": {
"buckets": [
{
"key": "music",
"doc_count": 2
},
{
"key": "forestry",
"doc_count": 1
},
{
"key": "sports",
"doc_count": 1
}
]
}
}
}

广告名词解释-Ad Network

发表于 2019-04-11 | 分类于 计算广告 | 评论数:

Ad Network 广告网络平台

阅读全文 »
1234
Craze lee

Craze lee

做个有温度的人

40 日志
16 分类
19 标签
Wechat
推荐阅读
  • 推荐阅读1
  • 推荐阅读2
© 2019 Craze lee
由 Hexo 强力驱动 v3.8.0
|
主题 – NexT.Pisces v7.0.0
|