Elasticsearch檢索 — 聚合和LBS

原文:https://www.fanhaobai.com/2017/08/elasticsearch-advanced-search.html

文章 Elasticsearch檢索實戰(zhàn) 已經(jīng)講述了 Elasticsearch 基本檢索使用,已滿足大部分檢索場景枪向,但是某些特定項目中會使用到 聚合LBS 這類高級檢索晕粪,以滿足檢索需求。這里將講述 Elasticsearch 的聚合和 LBS 檢索使用方法盆犁。

本文示例的房源數(shù)據(jù)抛人,見這里,檢索同樣使用 Elasticsearch 的 DSL 對比 SQL 來說明。

聚合

常規(guī)聚合

aggs 子句聚合是 Elasticsearch 常規(guī)的聚合實現(xiàn)方式省撑。

桶和指標

先理解這兩個基本概念:

名稱 描述
桶(Buckets) 滿足特定條件的文檔的集合
指標(Metrics) 對桶內(nèi)的文檔進行統(tǒng)計計算

每個聚合都是 一個或者多個桶和零個或者多個指標 的組合,聚合可能只有一個桶俯在,可能只有一個指標竟秫,或者可能兩個都有。例如這個 SQL:

SELECT COUNT(field_name) FROM table GROUP BY field_name

其中COUNT(field_name)相當于指標跷乐,GROUP BY field_name相當于桶肥败。桶在概念上類似于 SQL 的分組(GROUP BY),而指標則類似于 COUNT() 愕提、 SUM() 馒稍、 MAX() 等統(tǒng)計方法。

桶和指標的可用取值列表:

分類 操作符 描述
terms 按精確值劃分桶
指標 sum 桶內(nèi)對該字段值求總數(shù)
指標 min 桶內(nèi)對該字段值求最小值
指標 max 桶內(nèi)對該字段值求最大值
指標 avg 桶內(nèi)對該字段值求平均數(shù)
指標 cardinality( 基數(shù)) 桶內(nèi)對該字段不同值的數(shù)量(distinct 值)

簡單聚合

Elasticsearch 聚合 DSL 描述如下:

"aggs" : { 
    "aggs_name" : {
        "operate" : { "field" : "field_name" }
    }
}

其中浅侨,aggs_name 表示聚合結(jié)果返回的字段名纽谒,operate 表示桶或指標的操作符名,field_name 為需要進行聚合的字段如输。

  • 例1鼓黔,統(tǒng)計西二旗每個小區(qū)的房源數(shù)量:
-- SQL描述
SELECT resblockId, COUNT(resblockId) FROM rooms WHERE bizcircleCode = 611100314 GROUP BY resblockId

Elasticsearch 聚合為:

{
  "query": {
    "constant_score": {
      "filter": {
        "bool": {
          "must": [{ "term": { "bizcircleCode": 611100314 }}]
        }
      }
    }
  },
  "aggs": {
    "resblock_list": {
      "terms": { "field": "resblockId" }
    }
  }
}

聚合結(jié)果如下:

{
"hits": {
  "total": 6,
  "max_score": 1,
  "hits": [... ...]
},
"aggregations": {
  "resblock_list": {
     "doc_count_error_upper_bound": 0,
     "sum_other_doc_count": 0,
     "buckets": [
        {
          "key": 1321052240532, //小區(qū)id為1321052240532有4間房
          "doc_count": 4
        },
        {
          "key": 1111047349969,//小區(qū)id為1111047349969有1間房
          "doc_count": 1
        },
        {
          "key": 1111050770108,//小區(qū)id為1111050770108有1間房
          "doc_count": 1
        }
     ]
  }
}}

可見,此時聚合的結(jié)果有且只有分組后文檔的 數(shù)量不见,只適合做一些分組后文檔數(shù)的統(tǒng)計澳化。

  • 例2,去重統(tǒng)計西二旗小區(qū)的數(shù)量:
-- SQL描述
SELECT COUNT(DISTINCT resblockId) FROM rooms WHERE bizcircleCode = 611100314

使用 cardinality 指標統(tǒng)計:

{
  "aggs": {
    "resblock_count": {
      "cardinality": {
        "field": "resblockId"
      }
    }
  }
}

添加度量指標

上述的簡單聚合脖祈,雖然可以統(tǒng)計桶內(nèi)的文檔數(shù)量肆捕,但是沒法實現(xiàn)組內(nèi)的其他指標統(tǒng)計刷晋,比如小區(qū)內(nèi)的最低房源價格盖高,這時就可以給桶添加一個 min 指標。

-- SQL描述
SELECT resblockId, MIN(price) FROM rooms WHERE bizcircleCode = 611100314

添加 min 指標后為:

{
  "aggs": {
    "resblock_list": {
      "terms": { "field": "resblockId" },
      "aggs": {
        "min_price": {
          "min": { "field": "price" }
        }
      }
    }
  }
}

結(jié)果為:

"buckets": [
  {
    "key": 1321052240532,
    "doc_count": 4,
    "min_price": {
      "value": 3320
    }
  }
]

嵌套桶

當然桶與桶之間也可以進行嵌套眼虱,這樣就能滿足復雜的聚合場景了喻奥。

例如,統(tǒng)計每個商圈的房源價格分布情況:

-- SQL描述
SELECT bizcircleCode, GROUP_CONCAT(price) FROM rooms WHERE cityCode = 110000 GROUP BY bizcircleCode

桶聚合實現(xiàn)如下:

{
  "aggs": {
    "bizcircle_price": {
      "terms": { "field": "bizcircleCode" },
      "aggs": {
        "price_list": {
          "terms": { "field": "price" }
        }
      }
    }
  }
}

聚合結(jié)果如下:

{
  "bizcircle_price": {
  "doc_count_error_upper_bound": 0,
  "sum_other_doc_count": 0,
  "buckets": [
    {
      "key": 18335745,
      "doc_count": 1,
      "price_list": {
      "buckets": [
        {
          "key": 3500,
          "doc_count": 1
        }
      ]
    },
    ... ...
  ]
}

增加文檔信息

通常情況下捏悬,聚合只返回了統(tǒng)計的一些指標撞蚕,當需要獲取聚合后每組的文檔信息(小區(qū)的名字和坐標等)時,該怎么處理呢过牙?這時甥厦,使用 top_hits 子句就可以實現(xiàn)纺铭。

例如,獲取西二旗每個小區(qū)最便宜的房源信息:

{
  "aggs": {
    "rooms": {
      "top_hits": {
        "size": 1,
        "sort": { "price": "asc" },
        "_source": []
      }
    }
  }
}

其中刀疙,size 為組內(nèi)返回的文檔個數(shù)舶赔,sort 表示組內(nèi)文檔的排序規(guī)則,_source 指定組內(nèi)文檔返回的字段谦秧。

聚合后的房源信息:

{
  "bizcircle_price": {
    "buckets": [
    {
      "key": 1111050770108,
      "doc_count": 1,
      "rooms": {
        "hits": {
          "total": 1,
          "hits": [
            {
              "_index": "rooms",
              "_source": {
                "resblockId": 1111050770108,
                "resblockName": "領秀慧谷C區(qū)",
                "size": 15.3,
                "bizcircleName": [ "西二旗", "回龍觀" ],
                "location": "40.106349,116.31051",
              },
              "sort": [ 3500 ]
           }
         ]
       }
     }
    }]
  }
}

字段折疊

從 Elasticsearch 5.0 之后竟纳,增加了一個新特性 field collapsing(字段折疊),字段折疊就是特定字段進行合并并去重疚鲤,然后返回結(jié)果集锥累,該功也能實現(xiàn) agg top_hits 的聚合效果。

例如集歇, 增加文檔信息 部分的獲取西二旗每個小區(qū)最便宜的房源信息桶略,可以實現(xiàn)為:

{
  "collapse": {
    "field": "resblockId",  //按resblockId字段進行折疊
    "inner_hits": {
      "name": "top_price", //房源信息結(jié)果鍵名
      "size": 1,           //每個折合集文檔數(shù)
      "sort": [            //每個折合集文檔排序規(guī)則
        { "price": "desc" }
      ],
      "_source": []        //文檔的字段
    }
  }
}

檢索結(jié)果如下:

{
  "hits": {
    "total": 7,
    "hits": [
    {
      "_index": "rooms",
      "_score": 1,
      "_source": {
        "resblockId": 1111050770108,
        "resblockName": "領秀慧谷C區(qū)",
        ... ...
      },
      "fields": {
        "resblockId": [ 1111050770108 ]
      },
      "inner_hits": {
        "top_price": {
          "hits": {
            "total": 1,
            "hits": [ 
            { 
              "_index": "rooms",
              "_source": {
                "resblockId": 1111050770108,
                "resblockName": "領秀慧谷C區(qū)",
                "price": 3500,
                ... ...
                "location": "40.106349,116.31051"
              },
              "sort": [ 3500 ]
            }]
          }
        }
      }
    ]
  }
}

Field collapsing 和 agg top_hits 區(qū)別:field collapsing 的結(jié)果是夠精確,同時速度較快鬼悠,更支持分頁功能删性。

LBS

Elasticsearch 同樣也支持了空間位置檢索,即可以通過地理坐標點進行過濾檢索焕窝。

索引格式

由于地理坐標點不能被動態(tài)映射自動檢測蹬挺,需要顯式聲明對應字段類型為 geo-point,如下:

PUT /rooms   //索引名

{
  "mappings": {
    "restaurant": {
      "properties": {
        ... ...
        "location": {          //空間位置檢索字段
          "type": "geo_point"  //字段類型
        }
      }
    }
  }
}

數(shù)據(jù)格式

當需檢索字段類型設置成 geo_point 后它掂,推送的經(jīng)緯度信息的形式可以是字符串巴帮、數(shù)組或者對象,如下:

形式 符號 示例
字符串 “l(fā)at,lon” “40.060937,116.315943”
對象 lat 和 lon { “l(fā)at”:40.060937, “l(fā)on”:116.315943 }
數(shù)組 [lon, lat] [116.315943, 40.060937]

特別需要注意數(shù)組形式時 lon 與 lat 的前后位置虐秋,不然就果斷踩坑了榕茧。

然后,推送含有經(jīng)緯度的數(shù)據(jù):

POST /rooms/room/

{
  "resblockId": 1321052240532,
  "resblockName": "領秀新硅谷1號院",
  "houseId": 1112046338679,
  "cityCode": 110000,
  "size": 14,
  "bizcircleCode": [ 611100314 ],
  "bizcircleName": [ "西二旗" ],
  "price": 3330,
  "location": "40.060937,116.315943"
}

檢索過濾方式

Elasticsearch 中支持 4 種地理坐標點過濾器客给,如下表:

名稱 描述
geo_distance 找出與指定位置在給定距離內(nèi)的點
geo_distance_range 找出與指定點距離在最小距離和最大距離之間的點
geo_bounding_box 找出落在指定矩形框中的點
geo_polygon 找出落在多邊形中的點用押,將不說明

例如,查找西二旗地鐵站 4km 的房源信息:

{
  "filter": {              //過濾器
    "geo_distance": {
      "distance": "4km",
      "location": {
        "lat": 40.106349,
        "lon": 116.31051
      }
    }
  }
}

LBS 檢索的結(jié)果為:

{
  "hits": [
    {
      "_index": "rooms",
      "_source": {
        "resblockId": 1111050770108,
        "resblockName": "領秀慧谷C區(qū)",
        ... ...
        "location": "40.106349,116.31051"
      }
    },
    {
      "_index": "rooms",
      "_source": {
        "resblockId": 1111047349969,
        "resblockName": "融澤嘉園",
        ... ...
        "location": "40.074203,116.315445"
      }
    }
  ]
}

總結(jié)

本文講述了使用 Elasticsearch 進行 聚合LBS 檢索靶剑,盡管文中只是以示例形式進行說明蜻拨,會存在很多不全面的地方,還是希望對你我學習 Elasticsearch 能有所幫助桩引。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缎讼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子坑匠,更是在濱河造成了極大的恐慌血崭,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異夹纫,居然都是意外死亡咽瓷,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進店門舰讹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來忱详,“玉大人,你說我怎么就攤上這事跺涤⌒僬觯” “怎么了?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵桶错,是天一觀的道長航唆。 經(jīng)常有香客問我,道長院刁,這世上最難降的妖魔是什么糯钙? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮退腥,結(jié)果婚禮上任岸,老公的妹妹穿的比我還像新娘。我一直安慰自己狡刘,他們只是感情好享潜,可當我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著嗅蔬,像睡著了一般剑按。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上澜术,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天艺蝴,我揣著相機與錄音,去河邊找鬼鸟废。 笑死猜敢,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的盒延。 我是一名探鬼主播缩擂,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼兰英!你這毒婦竟也來了撇叁?” 一聲冷哼從身側(cè)響起供鸠,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤畦贸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體薄坏,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡趋厉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了胶坠。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片君账。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖沈善,靈堂內(nèi)的尸體忽然破棺而出乡数,到底是詐尸還是另有隱情,我是刑警寧澤闻牡,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布净赴,位于F島的核電站,受9級特大地震影響罩润,放射性物質(zhì)發(fā)生泄漏玖翅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一割以、第九天 我趴在偏房一處隱蔽的房頂上張望金度。 院中可真熱鬧,春花似錦严沥、人聲如沸猜极。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽魔吐。三九已至,卻和暖如春莱找,著一層夾襖步出監(jiān)牢的瞬間酬姆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工奥溺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留辞色,地道東北人。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓浮定,卻偏偏與公主長得像相满,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子桦卒,可洞房花燭夜當晚...
    茶點故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 原文:https://www.fanhaobai.com/2017/08/elasticsearch-search...
    Howborn閱讀 2,256評論 0 5
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理立美,服務發(fā)現(xiàn),斷路器方灾,智...
    卡卡羅2017閱讀 134,715評論 18 139
  • 博客原文一博客原文二 翻譯作品建蹄,水平有限碌更,如有錯誤,煩請留言指正洞慎。原文請見 官網(wǎng)英文文檔 起步 Elasticse...
    rabbitGYK閱讀 3,261評論 0 68
  • Solr&ElasticSearch原理及應用 一痛单、綜述 搜索 http://baike.baidu.com/it...
    樓外樓V閱讀 7,305評論 1 17
  • 引 “十二點了啊,這么晚劲腿,小成應該已經(jīng)睡了吧”阿文最近不知道怎么了旭绒,總覺得家里面充滿了不對勁,但是他又說不上來到底...
    說說侃侃聊聊閱讀 246評論 0 1