Elasticsearch 具有良好的默认设置,并且只需要很少的配置。可以使用 cluster-update-setting API 在正在运行的集群上更改大多数设置。

配置文件应包含特定于节点的设置(例如 node.name 和路径),或节点为了能够加入集群所需的设置,例如 cluster.namenetwork.host

配置文件位置

Elasticsearch 具有三个配置文件:

  • elasticsearch.yml 用于配置 Elasticsearch
  • jvm.options 用于配置 Elasticsearch JVM 设置
  • log4j.properties 用于配置 Elasticsearch 日志记录

这些文件位于 config 目录中,其默认位置取决于安装是来自自归档发行版(tar.gzzip)还是软件包发行版(Debian 或 RPM 软件包)。

对于存档分发,配置目录位置默认为 $ES_HOME/config。可以通过 ES_PATH_CONF 环境变量来更改 config 目录的位置,如下所示:

1
ES_PATH_CONF=/path/to/my/config ./bin/elasticsearch

或者,您可以通过命令行或外壳配置文件来 export 使用 ES_PATH_CONF 环境变量。

对于软件包分发,config 目录位置默认为 /etc/elasticsearch。config 目录的位置也可以通过 ES_PATH_CONF 环境变量来更改,但是请注意,在你的 shell 中进行设置是不够的。而是,此变量来自 /etc/default/elasticsearch (对于 Debian 软件包) 和 /etc/sysconfig/elasticsearch (对于 RPM 软件包)。您将需要相应地 ES_PATH_CONF=/etc/elasticsearch 在这些文件之一中编辑条目,以更改配置目录位置。

配置文件格式

配置格式为 YAML。这是更改数据和日志目录的路径的示例。

1
2
3
path:
data: /var/lib/elasticsearch
logs: /var/log/elasticsearch

设置也可以按照如下方式展平:

1
2
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch

环境变量替换

${...} 在配置文件中用符号引用的环境变量将替换为环境变量的值。例如:

1
2
node.name: ${HOSTNAME}
network.host: ${ES_NETWORK_HOST}

环境变量的值必须是简单的字符串。使用逗号分隔的字符串,Elasticsearch 将解析为列表。例如,Elasticsearch 将以下字符串拆分为 ${HOSTNAME} 环境变量的值列表:

1
export HOSTNAME="host1, host2"

集群和节点设置类型

可以根据配置方式对集群和节点进行分类:

动态

你可以使用 cluster-update-API 在正在运行的集群上配置和更新动态设置。

你还可以使用来在未启动或关闭的节点上本地配置动态设置 elasticsearch.yml

最好使用 cluster-update-API 设置动态,集群范围内的设置,并且 elasticsearch.yml 仅用于本地配置。使用集群更新 API 可以确保所有节点上的设置都相同。如果您不小心在不同的接点上配置了不同的设置,则可能很难注意到差异。

静态的

只能使用在未启动或关闭的节点上配置静态设置 elasticsearch.yml

必须在集群中的每个相关节点上设置静态设置。

Elasticsearch 聚合使你能够获取有关搜索结果的元信息,并回答诸如 “德克萨斯州有多少账户持有人?” 之类的问题。或 “田纳西州的平均账户余额是多少?” 你可以在一个请求中搜索文档,过滤匹配,并使用汇总分析结果。

例如,以下请求使用 terms 汇总将 bank 索引中的所有账户按状态分组,并按降序返回账户数量最多的十个州:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$params = [
'index' => 'bank',
'body' => [
'size' => 0,
'aggs' => [
'group_by_state' => [
'terms' => [
'field' => 'state.keyword',
],
],
],
],
];
$response = $client->search($params);

响应结果中的 bucketsstate 字段的值,doc_count 是每一个州的账户数量。例如,你可以看到有 27 个账户在 ID(Idaho)。因为请求设置了 size=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
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
56
57
58
59
60
61
62
63
64
65
66
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1000,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"group_by_state": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 743,
"buckets": [
{
"key": "TX",
"doc_count": 30
},
{
"key": "MD",
"doc_count": 28
},
{
"key": "ID",
"doc_count": 27
},
{
"key": "AL",
"doc_count": 25
},
{
"key": "ME",
"doc_count": 25
},
{
"key": "TN",
"doc_count": 25
},
{
"key": "WY",
"doc_count": 25
},
{
"key": "DC",
"doc_count": 24
},
{
"key": "MA",
"doc_count": 24
},
{
"key": "ND",
"doc_count": 24
}
]
}
}
}

你可以组合聚合以构建更复杂的数据汇总。例如,以下请求将一个 avg 聚合嵌套在先前的 group_by_state 聚合中,以计算每个状态的平均账户余额。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$params = [
'index' => 'bank',
'body' => [
'size' => 0,
'aggs' => [
'group_by_state' => [
'terms' => [
'field' => 'state.keyword',
],
'aggs' => [
'average_balance' => [
'avg' => [
'field' => 'balance',
],
],
],
],
],
],
];

$response = $client->search($params);

结果:

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
{
"took": 19,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1000,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"group_by_state": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 743,
"buckets": [
{
"key": "TX",
"doc_count": 30,
"average_balance": {
"value": 26073.3
}
},
{
"key": "MD",
"doc_count": 28,
"average_balance": {
"value": 26161.535714285714
}
},
{
"key": "ID",
"doc_count": 27,
"average_balance": {
"value": 24368.777777777777
}
},
{
"key": "AL",
"doc_count": 25,
"average_balance": {
"value": 25739.56
}
},
{
"key": "ME",
"doc_count": 25,
"average_balance": {
"value": 21663
}
},
{
"key": "TN",
"doc_count": 25,
"average_balance": {
"value": 28365.4
}
},
{
"key": "WY",
"doc_count": 25,
"average_balance": {
"value": 21731.52
}
},
{
"key": "DC",
"doc_count": 24,
"average_balance": {
"value": 23180.583333333332
}
},
{
"key": "MA",
"doc_count": 24,
"average_balance": {
"value": 29600.333333333332
}
},
{
"key": "ND",
"doc_count": 24,
"average_balance": {
"value": 26577.333333333332
}
}
]
}
}
}

你可以通过指定 terms 聚合内的顺序来使用嵌套聚合的结果进行排序,而不是按计数进行排序:

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
$params = [
'index' => 'bank',
'body' => [
'size' => 0,
'aggs' => [
'group_by_state' => [
'terms' => [
'field' => 'state.keyword',
'order' => [
'average_balance' => 'desc',
],
],
'aggs' => [
'average_balance' => [
'avg' => [
'field' => 'balance',
],
],
],
],
],
],
];

$response = $client->search($params);

结果:

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
{
"took": 9,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1000,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"group_by_state": {
"doc_count_error_upper_bound": -1,
"sum_other_doc_count": 827,
"buckets": [
{
"key": "CO",
"doc_count": 14,
"average_balance": {
"value": 32460.35714285714
}
},
{
"key": "NE",
"doc_count": 16,
"average_balance": {
"value": 32041.5625
}
},
{
"key": "AZ",
"doc_count": 14,
"average_balance": {
"value": 31634.785714285714
}
},
{
"key": "MT",
"doc_count": 17,
"average_balance": {
"value": 31147.41176470588
}
},
{
"key": "VA",
"doc_count": 16,
"average_balance": {
"value": 30600.0625
}
},
{
"key": "GA",
"doc_count": 19,
"average_balance": {
"value": 30089
}
},
{
"key": "MA",
"doc_count": 24,
"average_balance": {
"value": 29600.333333333332
}
},
{
"key": "IL",
"doc_count": 22,
"average_balance": {
"value": 29489.727272727272
}
},
{
"key": "NM",
"doc_count": 14,
"average_balance": {
"value": 28792.64285714286
}
},
{
"key": "LA",
"doc_count": 17,
"average_balance": {
"value": 28791.823529411766
}
}
]
}
}
}

除了这些基本的聚合外,Elasticsearch 还提供了专门的聚合,用于在多个字段上操作并分析特定类型的数据,例如日期,IP 地址和地理数据。您还可以将单个聚合的结果发送到聚合管道中,以便进行进一步分析。

聚合提供的核心分析功能可启用高级功能,例如使用机器学习来检测异常。

不做任何过滤的搜索

一旦将一些数据摄取到 Elasticsearch 索引之后,你就可以通过 /{index}/_search 来发起搜索请求。要访问全套搜索功能,请使用 Elasticsearch Query DSL 在请求正文中指定搜索条件。您可以在请求 URI 中指定搜索的索引的名称。

例如,以下请求检索 bank 按账号排序的索引中的所有文档:

1
2
3
4
5
6
7
GET /bank/_search
{
"query": { "match_all": {} },
"sort": {
{ "account_number": "asc" }
}
}

PHP 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$params = [
'index' => 'bank',
'body' => [
'query' => [
'match_all' => (object)[
],
],
'sort' => [
[
'account_number' => 'asc',
],
],
],
];
$response = $client->search($params);

'match_all' 后面如果是空数组,需要加上 (object) 转换成空对象。

默认情况下,返回值的 hits 字段包含了符合搜索条件的前十条文档:

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
{
"took" : 63,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value": 1000,
"relation": "eq"
},
"max_score" : null,
"hits" : [ {
"_index" : "bank",
"_id" : "0",
"sort": [0],
"_score" : null,
"_source" : {"account_number":0,"balance":16623,"firstname":"Bradshaw","lastname":"Mckenzie","age":29,"gender":"F","address":"244 Columbus Place","employer":"Euron","email":"bradshawmckenzie@euron.com","city":"Hobucken","state":"CO"}
}, {
"_index" : "bank",
"_id" : "1",
"sort": [1],
"_score" : null,
"_source" : {"account_number":1,"balance":39225,"firstname":"Amber","lastname":"Duke","age":32,"gender":"M","address":"880 Holmes Lane","employer":"Pyrami","email":"amberduke@pyrami.com","city":"Brogan","state":"IL"}
}, ...
]
}
}

响应结果也提供了关于搜索请求的一些其他信息:

  • took: 单位为 ms,Elasticsearch 处理这个请求用了多久
  • timed_out: 搜索请求是否超时
  • _shards: 搜索了多少个分片,以及成功、失败或跳过了多少个分片
  • max_score: 找到的最相关文件的分数
  • hits.total.value: 找到了多少个匹配的文档
  • hits.sort: 文档的排序(不按相关性得分排序时)
  • hits._score: 文档的相关性得分(使用时不适用 match_all

每个请求是独立的:Elasticsearch 在请求中不维护任何状态信息。要翻阅搜索结果,请在您的请求中指定 fromsize 参数。

例如,以下请求获取了第 10 到 19 条文档:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$params = [
'index' => 'bank',
'body' => [
'query' => [
'match_all' => (object)[
],
],
'sort' => [
[
'account_number' => 'asc',
],
],
'from' => 10,
'size' => 10,
],
];

$response = $client->search($params);

根据字段匹配搜索

不精确匹配

既然已经了解了如何提交基本的搜索请求,则可以开始构建更有趣的 match_all 查询。

要在字段中搜索特定术语,可以使用 match 查询。例如,以下请求搜索该 address 字段以查找地址包含 milllane 的客户:

1
2
3
4
5
6
7
8
9
10
11
12
$params = [
'index' => 'bank',
'body' => [
'query' => [
'match' => [
'address' => 'mill lane',
],
],
],
];

$response = $client->search($params);

精确匹配

如果要执行词组搜索而不是匹配单个词,请使用 match_phrase 代替 match。例如,以下请求仅匹配包含短语 mill lane 的地址:

1
2
3
4
5
6
7
8
9
10
11
12
$params = [
'index' => 'bank',
'body' => [
'query' => [
'match_phrase' => [
'address' => 'mill lane',
],
],
],
];

$response = $client->search($params);

要想构造更复杂的查询,可以使用 bool 查询来组合多个查询条件。你可以根据需要(必须匹配),期望(应该匹配)或不期望(必须不匹配)指定条件。

例如,以下请求在 bank 索引中搜索属于 40 岁客户的账户,但不包括住在爱达荷州(ID)的任何人:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$params = [
'index' => 'bank',
'body' => [
'query' => [
'bool' => [
'must' => [
'match' => [
'age' => '40',
],
],
'must_not' => [
[
'match' => [
'state' => 'ID',
],
],
],
],
],
],
];
$response = $client->search($params);

bool 查询中的每个 mustshouldmust_not 元素成为查询子句。文档满足每个 mustshould 的标准的程度有助于文档的相关性得分。分数越高,文档就越符合你的搜索条件。默认情况下,Elasticsearch 返回按这些相关性分数排名的文档。

must_not 子句中的条件被视为过滤器。它影响文件是否包含在结果中,但不会影响文件的评分方式。您还可以显式指定任意过滤器,以基于结构化数据包括或排除文档。

例如,以下请求使用范围过滤器将结果限制为余额在 2000 美元到 30000 美元(含)之间的账户。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$params = [
'index' => 'bank',
'body' => [
'query' => [
'bool' => [
'must' => [
'match_all' => [
],
],
'filter' => [
'range' => [
'balance' => [
'gte' => 20000,
'lte' => 30000,
],
],
],
],
],
],
];

$response = $client->search($params);

索引单个文档

我们可以使用一个 PUT 请求来索引单个文档:

1
2
3
4
PUT /customer/_doc/1
{
"name": "John Doe"
}
  • 使用 PUT 方法
  • customer: 索引名称
  • 1: 唯一的文档 ID
  • body: 文档内容,可以包含一个或多个键值对

如果索引不存在,则 Elasticsearch 会新建一个,然后存储该文档。

因为这是一个新的文档,所以响应结果显示文档的版本为 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"_index" : "customer",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 26,
"_primary_term" : 4
}

获取单个文档

我们可以通过一个 GET 请求来获取刚刚保存进索引的文档:

1
GET /customer/_doc/1

这里的 1 是文档唯一 ID。

响应结果如下,_source 是原始文档内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"_index": "customer",
"_type": "_doc",
"_id": "1",
"_version": 2,
"_seq_no": 1,
"_primary_term": 1,
"found": true,
"_source": {
"h": [
"health",
"index",
"docs.count"
]
}
}

使用 bulk API 批量索引文档

如果你有很多要索引的文档,则可以使用 bulk API 批量提交。使用批量处理批处理文档操作比单独提交请求要快得多,因为它可以最大程度地减少网络往返次数。

导入测试数据

https://www.elastic.co/guide/en/elasticsearch/reference/master/getting-started-index.html#getting-started-index

1、获取下载链接

命令行直接下载会非常慢,这个只有依靠代理去解决了,我们可以从 vagrant box add 的命令输出中拿到 box 的下载链接, 然后去浏览器通过代理来下载。

2、下载之后,新建一个 metadata.json 文件,内容如下:

1
2
3
4
5
6
7
8
9
10
{
"name": "laravel/homestead",
"versions": [{
"version": "9.5.0",
"providers": [{
"name": "virtualbox",
"url": "file://C:/Users/ruby/Downloads/homestead.box"
}]
}]
}

这里的 C:/Users/ruby/Downloads/homestead.box 是下载的 box 保存的路径。

这里的版本号是我们 homestead up 的时候获取到的版本。

3、最后一步

1
homestead up
0%