測試數(shù)據(jù)
首先下載 elastic 官方的測試數(shù)據(jù):下載地址
通過 curl 上傳測試數(shù)據(jù)
curl -H "Content-Type: application/json" -XPOST "localhost:9200/bank/_doc/_bulk?pretty&refresh" --data-binary "@accounts.json"
curl "localhost:9200/_cat/indices?v"
也可以使用 postman 上傳 localhost:9200/bank/_doc/_bulk?pretty&refresh

不管使用什么方式上傳,如果上傳成功,返回的 response 都應(yīng)該是這樣的:
{
"took": 1016,
"errors": false,
"items": [
{
"index": {
"_index": "bank",
"_type": "_doc",
"_id": "1",
"_version": 1,
"result": "created",
"forced_refresh": true,
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1,
"status": 201
}
}
......
]
}
查詢
elastic 可以通過兩種方式查詢,一種是通過 URL 傳參方式,另種是通過 Body 傳 JSON 格式字符串的方式查詢。
URL 傳參方式查詢
首先我們來看一下 URL 傳參的方式
GET /bank/_search?q=*&sort=account_number:asc&pretty
Response
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1000,
"max_score" : null,
"hits" : [
{
"_index" : "bank",
"_type" : "_doc",
"_id" : "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"
},
"sort" : [
0
]
}, ...
]
}
仔細(xì)看一下就會能夠發(fā)現(xiàn),返回的的數(shù)據(jù)是以 account_number 升序排列的。
解釋一下上面查詢語句的作用,/bank/_search 查詢 bank 索引, q=* 表示所有文檔,sort=account_number 表示以 account_number 字段作為排序依據(jù),asc 表示升序排列,&pretty 是用來返回可讀性好的數(shù)據(jù)。
Body 傳 JSON 字符方式查詢
向下面這種 JSON 風(fēng)格的查詢語句,elastic 稱為 DSL 語句,它效果跟上面作用是一樣的,很明顯 DSL 可讀性比明顯好于上面的,下面將重點(diǎn)介紹 DSL 語句。
GET /bank/_search
{
"query": {
"match_all": {
}
}
, "sort": [
{
"account_number": {
"order": "asc" # desc 降序
}
}
]
}
DSL 查詢語句
首先來看個最簡單的例子,查詢 bank 索引中的所有文檔
GET /bank/_search
{
"query": { "match_all": {} }
}
size 指定返回文檔數(shù)量,默認(rèn)值是10(之前只有十條記錄就是這個原因),配合 form 可以達(dá)到跟 MySQL 中 limit 的類似的效果。
GET /bank/_search
{
"query": { "match_all": {} }
, "size": 2
}
查詢 10 ~ 19 的記錄 [10,20),from 的默認(rèn)值是 0
GET /bank/_search
{
"query": { "match_all": {} },
"from": 10,
"size": 10
}
通過上面我們已經(jīng)學(xué)會了 排序,跟獲取指定區(qū)間文檔了,現(xiàn)在來繼續(xù)學(xué)習(xí),通過看上面的返回值可以知道我們默認(rèn)返回的是整個文檔,我們能不能向 MySQL 那樣只查詢特定字段呢,答案是可以的,看下面示例。
只查詢文檔中的 account_number 和 balance 字段
GET /bank/_search
{
"query": { "match_all": {} },
"_source": ["account_number", "balance"]
}
Response (只截取了部分記錄)
{
"_index" : "bank",
"_type" : "_doc",
"_id" : "25",
"_score" : 1.0,
"_source" : {
"account_number" : 25,
"balance" : 40540
}
},
{
"_index" : "bank",
"_type" : "_doc",
"_id" : "44",
"_score" : 1.0,
"_source" : {
"account_number" : 44,
"balance" : 34487
}
}
精確查詢(對于字段類型為 數(shù)值的記錄),獲取 age = 37 的文檔
GET /bank/_search
{
"query": { "match": { "age": 37}}
}
模糊查詢(對于句子),查找 adress 中包含 mill 的文檔(不區(qū)分大小寫)
GET /bank/_search
{
"query": { "match": { "address": "mill" } }
}
查找 adress 中包含 mill 或 lane 的文檔(不區(qū)分大小寫)
GET /bank/_search
{
"query": { "match": { "address": "mill lane" } }
}
返回文檔中元數(shù)據(jù)中的 hits.hits._sroce 表示匹配得分,1 表示完全匹配,分?jǐn)?shù)越高排的越靠前。另外還需要注意的是 match 只能指定一個字段。這些規(guī)則對于下面的也適用。
bool qurey
must 需要同時匹配,and 關(guān)系,這個返回 adress 中包含 mill 和 lane 的文檔
GET /bank/_search
{
"query": {
"bool": {
"must": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}
should 匹配其中一個就可以了,or 關(guān)系,這個返回 adress 中包含 mill 或
lane的文檔
GET /bank/_search
{
"query": {
"bool": {
"should": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}
must_not 不匹配其中任何一個,是 nor(或非)的的關(guān)系,這個返回adress 中不包含 mill 或
lane的文檔
GET /bank/_search
{
"query": {
"bool": {
"must_not": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}
他們還可以組合使用,讓我們看下面這個例子,查詢 age = 24, state != ID 的顧客。
GET /bank/_search
{
"query": {
"bool": {
"must": [
{ "match": { "age": "24" } }
],
"must_not": [
{ "match": { "state": "ID" } }
]
}
}
, "size": 1
}
Response
"hits" : {
"total" : 42,
"max_score" : 1.0,
"hits" : [
{
"_index" : "bank",
"_type" : "_doc",
"_id" : "335",
"_score" : 1.0,
"_source" : {
"account_number" : 335,
"balance" : 35433,
"firstname" : "Vera",
"lastname" : "Hansen",
"age" : 24,
"gender" : "M",
"address" : "252 Bushwick Avenue",
"employer" : "Zanilla",
"email" : "verahansen@zanilla.com",
"city" : "Manila",
"state" : "TN"
}
}
]
}
Filter 過濾條件
常用的條件操作符有:
- (>) 大于 -
gt - (<)小于 -
lt - (>=)大于等于 -
gte - (<= ) 小于等于 -
lte
查詢 age <= 20的用戶
GET /bank/_search
{
"query": {
"bool": {
"must": { "match_all": {} },
"filter": {
"range": {
"age": {
"lte": 20
}
}
}
}
}
}
還可以組合使用,下面的查詢 2000 <= balance <= 3000 的用戶
GET /bank/_search
{
"query": {
"bool": {
"must": { "match_all": {} },
"filter": {
"range": {
"balance": {
"gte": 20000,
"lte": 30000
}
}
}
}
}
}
聚合
看寫下面這個例子,統(tǒng)計男女人數(shù)(默認(rèn)是取前10,按統(tǒng)計數(shù)量降序排列),查詢效果相當(dāng)于 SQL:SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC LIMIT 10;
GET /bank/_search
{a
"size": 0,
"aggs": {
"group_by_gender": {
"terms": {
"field": "gender.keyword"
}
}
}
}
上面的size = 0 表示只看聚合結(jié)果,如果要聚合的字段是數(shù)值類型,直接使用字段名,后面不用加 .keyword,例如統(tǒng)計年齡人數(shù) "field": "age"
Response:
"hits" : {
"total" : 1000,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"group_by_gender" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "M",
"doc_count" : 507
},
{
"key" : "F",
"doc_count" : 493
}
]
}
}
設(shè)置數(shù)量
"terms": {
"field": "age"
, "size": 100
}
接下來我們來個稍微復(fù)雜一點(diǎn)的查詢,查詢 哪個年齡的用戶平均存款最多
GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_age": { # 可以自定義名字
"terms": {
"field": "age",
"order": {
"average_balance": "desc" # 依據(jù) average_balance 降序排列
}
, "size": 1 # 顯示最前面的 1 個
},
"aggs": {
"average_balance": { # 可以自定義名字
"avg": {
"field": "balance" # 分組后 balance 的平均值
}
}
}
}
}
}
Response:
"aggregations" : {
"group_by_age" : {
"doc_count_error_upper_bound" : -1,
"sum_other_doc_count" : 976,
"buckets" : [
{
"key" : 29,
"doc_count" : 24,
"average_balance" : {
"value" : 33540.666666666664
}
}
]
}
}
關(guān)于查詢就先寫到這里,上面的都是看官方記錄的筆記,想了解更多內(nèi)容可以看官方文檔