概念
在上個小節,我們學習了geo_point
的數據類型。
這一小節我們來學習geo_shape
數據類型,它有助於索引和搜索 任意地理形狀,例如矩形和多邊形。當正在索引的數據或正在執行的查詢包含除點以外的其他形狀時,應使用它。
通過上面的概念描述,我們可以得出geo_point
和geo_shape
的最大區別是: geo_point
表示一個點;geo_shape
則表示有多個點連成線組成的形狀。 學過數學的肯定很容易理解。
實際開發中,如果我們的地理座標是一個地理形狀,則可以使用地理形狀數據類型進行插入、查詢文檔。比如說學校、大商場這種面積比較大的地理座標,都需要geo_shape
來表示。
- mapping params
geo_shape
映射將geo_json
幾何對象映射到geo_shape
類型。要啓用它,用戶必須將字段顯式映射到geo_shape
類型。
地理形狀數據類型的參數選項
選項 | 說明 | 默認值 |
---|---|---|
tree | 將使用的PrefixTree實現的名稱:GeohashPrefixTree爲geohash,QuadPrefixTree爲quadtree。 | geohash |
precision | 可以使用此參數代替tree_levels來爲tree_levels參數設置適當的值。該值指定所需的精度,Elasticsearch將計算最佳的tree_levels值以兌現該精度。該值應爲數字,後跟可選的距離單位。有效距離單位包括:英寸,英寸,碼,碼,英里,英里,公里,公里,米,米,釐米,釐米,毫米,毫米。 | meters |
tree_levels | PrefixTree使用的最大層數。這可用於控制形狀表示的精度,從而控制索引多少項。默認爲所選PrefixTree實現的默認值。由於此參數要求對底層實現有一定程度的瞭解,因此用戶可以改用precision參數。但是,Elasticsearch僅在內部使用tree_levels參數,即使您使用precision參數,這也是通過映射API返回的結果 | 50m |
strategy | 策略參數定義瞭如何在索引和搜索時表示形狀的方法。它還會影響可用的功能,因此建議讓Elasticsearch自動設置此參數。有兩種可用的策略:遞歸和術語。術語策略僅支持點類型(points_only參數將自動設置爲true),而遞歸策略則支持所有形狀類型。(重要:請參見前綴樹以獲取更多詳細信息) | recursive |
distance_error_pct | 用作PrefixTree關於其精度的提示。默認值爲0.025(2.5%),最大支持值爲0.5。性能注意:如果明確定義了precision或tree_level定義,則此值將默認爲0。這樣可以保證映射中定義的級別的空間精度。對於低誤差的高分辨率形狀(例如,誤差小於0.001的1m大形狀),這可能會導致大量內存使用。爲了提高索引性能(以查詢準確性爲代價),顯式定義tree_level或precision以及合理的distance_error_pct,請注意,較大的形狀將具有更大的誤報率。 | 0.025 |
orientation | (可選)定義如何解釋多邊形/多多邊形的頂點順序。此參數定義兩個座標系規則(右手或左手)之一,可以用三種不同的方式來指定每個規則。1.右手規則:右,逆時針,逆時針2. 2.左手規則:左,順時針,順時針。默認方向(逆時針)符合OGC標準,該標準以逆時針順序定義外環頂點,而內環頂點(孔)以順時針順序定義。在geo_shape映射中設置此參數可顯式設置geo_shape字段的座標列表的頂點順序,但可以在每個單獨的GeoJSON文檔中覆蓋。 | ccw |
points_only | 將此選項設置爲true(默認爲false)可僅爲點形狀配置geo_shape字段類型(注意:尚不支持多點)。當已知僅索引點時,這將優化geohash和四叉樹的索引和搜索性能。目前,無法對geo_point字段類型執行geo_shape查詢。此選項通過改善geo_shape字段上的點性能來彌合差距,從而使geo_shape查詢在僅點字段上是最佳的。 | false |
ignore_malformed | 如果爲true,則會忽略格式錯誤的geojson形狀。如果爲假(默認),則格式錯誤的geojson形狀會引發異常並拒絕整個文檔。 | false |
- 前綴樹
爲了有效地表示索引中的形狀,使用PrefixTree的實現將Shapes轉換爲代表網格正方形的一系列哈希(通常稱爲“柵格”)。樹的概念來自這樣一個事實,即PrefixTree使用多個網格層,每個網格層的精度更高,以表示地球。
可以認爲這是在更高的縮放級別下增加地圖或圖像的細節級別。
es中提供了多個PrefixTree實現。
-
GeohashPrefixTree 對網格正方形使用geohash。Geohash是交錯的緯度和經度的位的base32編碼的字符串。
因此,哈希越長,它越精確。添加到geohash的每個字符代表另一個樹級別,併爲geohash增加5位精度。Geohash表示一個矩形區域,並具有32個子矩形。Elasticsearch中的最大級別數爲24。 -
QuadPrefixTree 對網格正方形使用四叉樹。與geohash相似,四叉樹將緯度和經度的比特交織在一起,結果哈希被置位。
四叉樹中的樹級別代表此位集中的2位,每個座標一個。Elasticsearch中四叉樹的最大級別數爲50。 -
空間策略
PrefixTree實現依賴於SpatialStrategy來將提供的Shape分解爲近似的網格正方形。每種策略都回答以下問題:
- 可以索引哪種類型的形狀?
- 可以使用哪些類型的查詢操作和形狀?
- 每個字段是否支持多個Shape?
提供以下策略實施(具有相應的功能):
策略 | 支持的形狀 | 支持的查詢 | 多個形狀 |
---|---|---|---|
recursive | All | INTERSECTS, DISJOINT, WITHIN, CONTAINS(相交,不相交,內含) | Yes |
term | Points | INTERSECTS (相交) | Yes |
- 準確性
Geo_shape
不提供100%的準確性,並且取決於它的配置方式,它可能對INTERSECTS
,WITHIN
和CONTAINS
查詢返回一些誤報,而對DISJOINT
查詢返回一些誤報。
爲了減輕這種情況,爲tree_levels
參數選擇適當的值並相應地調整期望很重要。例如,一個點可能在特定網格像元的邊界附近,因此可能與僅與它緊鄰的像元匹配的查詢不匹配-即使形狀非常接近該點。
示例使用
比如說我們有一些大商場的地理信息。我們想要實現在某個地理位置附近多少米範圍有哪些大商場?
1. mapping定義
PUT my_index
{
"mappings": {
"docs": {
"properties": {
"name": {"type": "text"},
"location": {
"type": "geo_shape"
}
}
}
}
}
2. 添加數據
PUT my_index/docs/1000
{
"name": "中心商場",
"location": {
"type": "point",
"coordinates": [121.392496,31.245827]
}
}
PUT my_index/docs/1001
{
"name": "城北商場",
"location": {
"type": "point",
"coordinates": [121.392496,31.30]
}
}
PUT my_index/docs/1002
{
"name": "城南商場",
"location": {
"type": "point",
"coordinates": [121.392496,31.013]
}
}
PUT my_index/docs/1003
{
"name": "城西商場",
"location": {
"type": "point",
"coordinates": [121.821,31.245827]
}
}
PUT my_index/docs/1004
{
"name": "城東商場",
"location": {
"type": "point",
"coordinates": [122.392496,31.245827]
}
}
上例中大量的方括號可能看起來讓人困惑,不過實際上 GeoJSON
的語法非常簡單.
-
用一個數組表示
經緯度
座標點[lon,lat]
-
一組座標點放到一個數組來表示一個多邊形
[[lon,lat],[lon,lat], ... ]
-
一個多邊形( polygon )形狀可以包含多個多邊形;第一個表示多邊形的外輪廓,後續的多邊形表示第一個多邊形內部的空洞
[
[[lon,lat],[lon,lat], ... ], # main polygon
[[lon,lat],[lon,lat], ... ], # hole in main polygon
...
]
3. 查詢
比如說查詢 查詢指定位置10KM範圍內的大商場信息數據。
GET my_index/docs/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": {
"geo_shape": {
"location": {
"shape": {
"type": "circle",
"radius": "10km",
"coordinates": [121.392496, 31.3]
}
}
}
}
}
}
}
返回結果集
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 1,
"hits": [
{
"_index": "my_index",
"_type": "docs",
"_id": "1001",
"_score": 1,
"_source": {
"name": "城北商場",
"location": {
"type": "point",
"coordinates": [
121.392496,
31.3
]
}
}
},
{
"_index": "my_index",
"_type": "docs",
"_id": "1000",
"_score": 1,
"_source": {
"name": "中心商場",
"location": {
"type": "point",
"coordinates": [
121.392496,
31.245827
]
}
}
}
]
}
}
發現有兩個商場符合條件。
後面有geo_shape更復雜的應用,在這裏我們的重點和學習geo_shape
這種類型概念和簡單使用。