刚接触Elasticsearch,对于习惯了Sql的我有点无所适从,看似天马行空的查询(搜索)语句让初入ES的小白我有点难以接受,但是对照着《elasticsearch权威指南》试着敲了几天python_elasticsearch API后,发现与SQL还是有大量相似之处,因此写下这一份笔记为方便后续再阅读。
前期准备:
1. 安装配置好ES,网上很多资料,这里不再复述;
2. 往ES中插入一些数据,这里可以调用python的ES API中index方法插入,这里我预先插入了类似于如下的数据
{
_index: "logstash-2018.01.09",
_type: "logs",
_id: "AWDaKEw14SpIsCUBj_Zd",
_score: 1,
_source: {
remote_addr: "11.11.11.11",
request: "GET /api/tag_info/?_id=1 HTTP/1.1",
body_bytes_sent: 102,
url: "/api/tag_info/",
http_user_agent: "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0",
remote_user: "-",
path: "/data/logs/nginx/net.log",
@timestamp: "2018-01-09T09:02:41.000Z",
http_referer: "http://192.168.1.2/tag_info/",
domain: "192.168.1.2",
@version: "1",
http_x_forwarded_for: "-",
host: "192.168.1.2",
responsetime: 0.002,
status: "200"
}
},
python要调用elasticsearch的查询,需要调用search(index, type, body, params)函数
1. 索引(index)、类型(type)的定义:
a. 查询时需要指定索引(index)与类型(type),我们可以理解为SQL需要指定库(databases)与表(table),查询条件写在body中,类似SQL中的where、order等
b. 索引(index)与类型(type)可以定义模糊字段,于SQL对照为select * from ind*.t*,类似search('ind*', 't*', {})
c. 甚至我们能定义多个索引多个类型,类似search('index1, index2', 'type1, type2', {}),search('_all', 'type1, type2', {})
以下是body的定义:
2. 单查询
a. 空查询,即查询所有数据(elasticsearch默认只查询10条,我们可以定义size),如下
body = {
'size': 100,
'query': {
'match_all': {}
}
}
以上语句类似于SQL的select * from index.type limit 100
b. 模糊匹配查询,若指定字段中的数据匹配了查询字符,则输出数据,并包含一个_score的匹配分数(分数越高,表示匹配度越高,默认排序越前)
body = {
'size': 100,
'query': {
'match': {
'body_bytes_sent': 102,
}
}
}
以上语句类似于SQL的 select * from index.type where body_bytes_send like '%102%' limit 100
c. 模糊多匹配查询,在多个字段中执行相同的match,若匹配上,则输出结果
body = {
'size': 100,
'query': {
'multi_match': {
'query': '10',
'fields': ['host', 'body_bytes_send']
}
}
}
以上语句类似于SQL的 select * from index.type where host like '%10%' or body_bytes_send like '%10%' limit 100
d. 精确匹配查询,若指定字段中的数据等于查询字符,则输出数据
body = {
'size': 100,
'query': {
'term': {
'@timestamp': '2018-01-09T09:02:41.000Z'
}
}
}
以上语句类似于SQL的 select * from index.type where @timestamp='2018-01-09T09:02:41.000Z' limit 100
e. 多值精确匹配,
body = {
'size': 100,
'query': {
'terms': {
'@timestamp': ['2018-01-09T09:02:41.000Z', '2018-01-09T10:35:21.000Z']
}
}
}
以上语句类似于SQL的 select * from index.type where
@timestamp in ('
2018-01-09T09:02:41.000Z
', '2018-01-09T10:35:21.000Z') limit 100
f. 指定数字或时间范围的匹配,当字段的类型为数字或者日期时,可以使用range指定查询的区间。这里需要对几个词语进行解释
gte (greaterthan andequal): >=
gt (greaterthan): >
lte (lessthan andequal): <=
lt (lessthan): <
body = {
'size': 100,
'query': {
'range': {
'body_bytes_sent': {
'lte': 102,
'gt': 0,
}
}
}
}
以上语句类似于SQL的 select * from index.type where body_bytes_sent>0 and
body_bytes_sent<=102 limit 100
g. 字段有值(exists)、字段无值(missing),返回字段非空(为空)的结果
body = {
'size': 100,
'query': {
'exists': {
'field': '@timestamp'
}
}
}
body = {
'size': 100,
'query': {
'missing': {
'field': '@timestamp'
}
}
}
以上语句类似于SQL的
select * from index.type where @timestamp not is null limit 100
select * from index.type where @timestamp is null limit 100
3. 复合查询
上面所写的都是单条查询,其实在使用时我们需要依据多个条件进行查询,类似于SQL中需要有and与or,因此这时候就需要复合查询来处理了。复合查询有如下关键字:
must:必须满足内部所有条件
must_not:必须不满足内部所有条件
should:满足内部任一条件,可为查询结果加分
filter:对结果进行再匹配(内部需要包含了must、must_not或者should),但是不会为结果进行近似度打分
如下例子可以展示一个复合查询
body = {
'size': 100, # 查询100条结果
'query': {
'bool': {
'must': [
{
'range': {
'body_bytes_sent': {
'gt': 0,
'lt': 100,
},
},
},
{
'match': {
'http_user_agent': 'AppleWebKit'
},
},
],
'filter': {
'bool': {
'must_not': [
{
'range': {
'body_bytes_sent': {
'gte': 20,
},
}
}
],
}
}
},
}
}
以上语句解析为:
a. body_bytes_sent必须在(0, 100)之间;
b. http_user_agent必须包含AppleWebKit,同时系统会为http_user_agent相似度进行评分
c. body_bytes_sent大于等于20必须不成立
最终结果需要同时满足a、b、c,同时a与b会影响最终查询结果的_score大小
若我们关心所有条件的匹配相似度,那上面的body修改成:
body = {
'size': 100,
'query': {
'bool': {
'must': [
{
'range': {
'body_bytes_sent': {
'gt': 0,
'lt': 100,
},
},
},
],
'must_not': [
{
'range': {
'body_bytes_sent': {
'gte': 20,
}
}
}
],
'should': [
{
'range': {
'body_bytes_sent': {
'lt': 20,
}
}
},
{
'match': {
'http_user_agent': 'AppleWebKit'
},
},
],
},
}
}
最终以上的语句我们可以理解为SQL:
select * from index.type where (body_bytes_sent>0 and body_bytes_sent<100) and (body_bytes_sent<20) and (body_bytes_sent<20 or http_user_agent like '%AppleWebKit%')
4. 结果排序
a. 在未指定排序时,查询结果是依据_score来进行的
b. 指定排序,如下例子
body = {
'size': 100,
'query': {
'range': {
'body_bytes_sent': {
'lte': 102,
'gt': 0,
}
}
},
'sort': {
'body_bytes_sent': {
'order': 'desc'(或者'asc')
}
}
}
以上语句类似于SQL:
select * from index.type where body_bytes_sent>0 and body_bytes_sent<=102 order by body_bytes_sent desc
其中desc为由大到小排序,asc为有小到大排序
c. 多级排序,如以下例子
body = {
'size': 100,
'query': {
'range': {
'body_bytes_sent': {
'lte': 102,
'gt': 0,
}
}
},
'sort': [
{
'body_bytes_sent': {
'order': 'desc'
}
},
{
'@timestamp': {
'order': 'asc'
}
},
]
}
这是在body_bytes_sent的基础上增加了@timestamp排序,在
body_bytes_sent相同的基础上会依据@timestamp从小到大继续排序
这一下我们了解了普通搜索,组合搜索与排序,聚合后续再写了。