快速上手
目录
什么是Elasticsearch
- 一个分布式的实时文档存储,每个字段 可以被索引与搜索
- 一个分布式实时分析搜索引擎
- 能胜任上百个服务节点的扩展,并支持 PB 级别的结构化或者非结构化数据
Elasticsearch 将所有的功能打包成一个单独的服务,这样便可以通过程序与它提供的简单的 RESTful API 进行通信, 可以使用自己喜欢的编程语言充当 web 客户端,甚至可以使用命令行(去充当这个客户端)
Elasticsearch为什么能支持复杂全文检索
Elasticsearch 是 面向文档 的,意味着它存储整个对象或 文档。Elasticsearch 不仅存储文档,而且 索引 每个文档的内容,使之可以被检索。在 Elasticsearch 中,我们对文档进行索引、检索、排序和过滤—而不是对行列数据。这是一种完全不同的思考数据的方式,也是 Elasticsearch 能支持复杂全文检索的原因。Elasticsearch 使用 JSON作为文档的序列化格式。JSON 序列化为大多数编程语言所支持,并且已经成为 NoSQL 领域的标准格式。 它简单、简洁、易于阅读。
Elasticsearch安装与使用
这里建议采用docker的方式安装Elasticsearch,非常的方便。
-
下载elasticsearch镜像,版本号为7.16.2。
docker pull elasticsearch:7.16.2 -
创建Elasticsearch实例
docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -e "discovery.type=single-node" -d -p 9200:9200 -p 9300:9300 --name elasticsearch e082d8ac7e5e -
验证Elasticsearch是否安装成功,访问 http://localhost:9200 ,返回一个Json,类似如下内容即为成功。
{ "name": "26b43d6e6429", "cluster_name": "docker-cluster", "cluster_uuid": "RBq5O2_XTfypnCJfFutoRA", "version": { "number": "7.16.2", "build_flavor": "default", "build_type": "docker", "build_hash": "2b937c44140b6559905130a8650c64dbd0879cfb", "build_date": "2021-12-18T19:42:46.604893745Z", "build_snapshot": false, "lucene_version": "8.10.1", "minimum_wire_compatibility_version": "6.8.0", "minimum_index_compatibility_version": "6.0.0-beta1" }, "tagline": "You Know, for Search" } -
查看Elasticsearch实例ip地址,我这里为172.17.0.3
-
下载kibana镜像,注意版本号匹配。
docker pull kibana:7.16.2 -
创建kibana实例,这里定义了一个环境变量ELASTICSEARCH_HOSTS对应的值就是elasticsearch实例的ip地址。
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://172.17.0.3:9200 -p 5601:5601 -d kibana:7.16.2 -
验证kibana是否安装成功,访问 http://localhost:5601 正常加载页面即为成功。
向Elasticsearch发送请求
使用REST API可以向Elasticsearch发送数据或者其他请求,这让你能够通过任意的客户端实现与Elasticsearch的交互,例如curl。当然也可以使用Kibana的控制台向Elasticsearch发送请求。
使用Kibana
-
点击Kibana主菜单,访问 Dev Tools > Console.

-
在console上执行下述样例API请求
GET /等价于使用curl执行以下命令
curl -X GET "localhost:9200/?pretty"
Elasticsearch数据管理
添加进Elasticsearch中的数据被称为文档,Elasticsearch将这些文档存储在可搜索的索引当中。对于时序类数据,例如日志和度量指标,通常可以将这些文档添加到一个由多个自动生成的后台索引组成的数据流当中。数据流需要与其名称匹配的索引模板。Elasticsearch 使用这个模板来配置数据流的后台索引。发送到数据流的文档必须存在一个@timestamp的字段。
添加一个文档
提交下列索引请求,将一条日志信息添加进logs-my_app-default数据流,如果该数据流不存在,那么该请求会使用logs-*-* 索引模板自动创建一个。
POST logs-my_app-default/_doc
{
"@timestamp": "2099-05-06T16:21:15.000Z",
"event": {
"original": "192.0.2.42 - - [06/May/2099:16:21:15 +0000] \"GET /images/bg.jpg HTTP/1.0\" 200 24736"
}
}
请求的响应的结果包含了Elasticsearch为这片文档自动生成的元数据:
- 这个后台索引
_index包含了该文档,而Elasticsearch自动生成了后台索引的名称。 - 该索引为为文档生成了一个唯一
id。
{
"_index": ".ds-logs-my_app-default-2099-05-06-000001",
"_type": "_doc",
"_id": "gl5MJXMBMk1dGnErnBW8",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
添加多条文档
使用_bulk端点可以在一个请求中添加多条文档。批量数据必须是用换行符分割JSON数据。每一个新的行都必须以\n结尾,包含最后一行。
PUT logs-my_app-default/_bulk
{ "create": { } }
{ "@timestamp": "2099-05-07T16:24:32.000Z", "event": { "original": "192.0.2.242 - - [07/May/2020:16:24:32 -0500] \"GET /images/hm_nbg.jpg HTTP/1.0\" 304 0" } }
{ "create": { } }
{ "@timestamp": "2099-05-08T16:25:42.000Z", "event": { "original": "192.0.2.255 - - [08/May/2099:16:25:42 +0000] \"GET /favicon.ico HTTP/1.0\" 200 3638" } }
搜索数据
被索引的文档在搜索时几乎是实时响应。下列搜索匹配的实体在logs-my_app-default中并且按照@timestamp降序排列。
GET logs-my_app-default/_search
{
"query": {
"match_all": { }
},
"sort": [
{
"@timestamp": "desc"
}
]
}
默认的,响应的命中部分包括最多与搜索匹配的前10个文档。每次命中的 _ source 包含索引期间提交的原始 JSON 对象。
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": null,
"hits": [
{
"_index": ".ds-logs-my_app-default-2099-05-06-000001",
"_type": "_doc",
"_id": "PdjWongB9KPnaVm2IyaL",
"_score": null,
"_source": {
"@timestamp": "2099-05-08T16:25:42.000Z",
"event": {
"original": "192.0.2.255 - - [08/May/2099:16:25:42 +0000] \"GET /favicon.ico HTTP/1.0\" 200 3638"
}
},
"sort": [
4081940742000
]
},
...
]
}
}
获取具体字段
对于大型文档来说,解析 完整的_source非常麻烦。若要从响应中排除它,请将 _source 参数设置为 false。相反,请使用 fields 参数检索所需的字段。
GET logs-my_app-default/_search
{
"query": {
"match_all": { }
},
"fields": [
"@timestamp"
],
"_source": false,
"sort": [
{
"@timestamp": "desc"
}
]
}
{
...
"hits": {
...
"hits": [
{
"_index": ".ds-logs-my_app-default-2099-05-06-000001",
"_type": "_doc",
"_id": "PdjWongB9KPnaVm2IyaL",
"_score": null,
"fields": {
"@timestamp": [
"2099-05-08T16:25:42.000Z"
]
},
"sort": [
4081940742000
]
},
...
]
}
}
搜索一个日期范围
若要跨特定时间或 IP 范围进行搜索,请使用范围查询。
GET logs-my_app-default/_search
{
"query": {
"range": {
"@timestamp": {
"gte": "2099-05-05",
"lt": "2099-05-08"
}
}
},
"fields": [
"@timestamp"
],
"_source": false,
"sort": [
{
"@timestamp": "desc"
}
]
}
可以使用日期数学来定义相对时间范围。以下查询搜索过去一天的数据,这些数据与日志logs-my_app-default中的任何日志条目都不匹配。
GET logs-my_app-default/_search
{
"query": {
"range": {
"@timestamp": {
"gte": "now-1d/d",
"lt": "now/d"
}
}
},
"fields": [
"@timestamp"
],
"_source": false,
"sort": [
{
"@timestamp": "desc"
}
]
}
从非结构化内容中提取字段
可以在搜索期间从非结构化内容(如日志消息)中提取运行时字段。使用以下搜索可以从event.original中提取 source.ip 运行时字段。要将其包含在响应中,请将 source.ip 添加到 fields 参数中。
GET logs-my_app-default/_search
{
"runtime_mappings": {
"source.ip": {
"type": "ip",
"script": """
String sourceip=grok('%{IPORHOST:sourceip} .*').extract(doc[ "event.original" ].value)?.sourceip;
if (sourceip != null) emit(sourceip);
"""
}
},
"query": {
"range": {
"@timestamp": {
"gte": "2099-05-05",
"lt": "2099-05-08"
}
}
},
"fields": [
"@timestamp",
"source.ip"
],
"_source": false,
"sort": [
{
"@timestamp": "desc"
}
]
}
组合查询
可以使用 bool 查询来组合多个查询。下面的搜索结合了两个范围查询: 一个在@timestamp上,一个在 source.ip 字段上。
GET logs-my_app-default/_search
{
"runtime_mappings": {
"source.ip": {
"type": "ip",
"script": """
String sourceip=grok('%{IPORHOST:sourceip} .*').extract(doc[ "event.original" ].value)?.sourceip;
if (sourceip != null) emit(sourceip);
"""
}
},
"query": {
"bool": {
"filter": [
{
"range": {
"@timestamp": {
"gte": "2099-05-05",
"lt": "2099-05-08"
}
}
},
{
"range": {
"source.ip": {
"gte": "192.0.2.0",
"lte": "192.0.2.240"
}
}
}
]
}
},
"fields": [
"@timestamp",
"source.ip"
],
"_source": false,
"sort": [
{
"@timestamp": "desc"
}
]
}
聚合数据
可以使用 bool 查询来组合多个查询。下面的搜索使用一个聚合来计算 average_response_size,该聚合使用http.response.body.bytes运行时字段。聚合仅在与query匹配的文档上运行。
GET logs-my_app-default/_search
{
"runtime_mappings": {
"http.response.body.bytes": {
"type": "long",
"script": """
String bytes=grok('%{COMMONAPACHELOG}').extract(doc[ "event.original" ].value)?.bytes;
if (bytes != null) emit(Integer.parseInt(bytes));
"""
}
},
"aggs": {
"average_response_size":{
"avg": {
"field": "http.response.body.bytes"
}
}
},
"query": {
"bool": {
"filter": [
{
"range": {
"@timestamp": {
"gte": "2099-05-05",
"lt": "2099-05-08"
}
}
}
]
}
},
"fields": [
"@timestamp",
"http.response.body.bytes"
],
"_source": false,
"sort": [
{
"@timestamp": "desc"
}
]
}
响应的aggregations对象包含聚合结果。
{
...
"aggregations" : {
"average_response_size" : {
"value" : 12368.0
}
}
}
清理数据
完成后,删除测试数据流
DELETE _data_stream/logs-my_app-default
参考
- quick start:www.elastic.co/guide/en/el…