This is an automated email from the ASF dual-hosted git repository.

wangdan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-pegasus-website.git


The following commit(s) were added to refs/heads/master by this push:
     new 25be6b46 Update GEO Chinese doc (#56)
25be6b46 is described below

commit 25be6b4615a77953af2ccb90e963cbfcd1ab11ea
Author: Yingchun Lai <[email protected]>
AuthorDate: Thu Jan 11 15:31:58 2024 +0800

    Update GEO Chinese doc (#56)
---
 _docs/zh/api/geo.md | 272 +++++++++++++++++++++++++++-------------------------
 1 file changed, 142 insertions(+), 130 deletions(-)

diff --git a/_docs/zh/api/geo.md b/_docs/zh/api/geo.md
index 2fc8624f..28c1eebb 100755
--- a/_docs/zh/api/geo.md
+++ b/_docs/zh/api/geo.md
@@ -2,197 +2,211 @@
 permalink: api/geo
 ---
 
-# Pegasus GEO支持
+# Pegasus GEO 支持
 
 ## 背景
 
-业务数据跟Pegasus的普通数据类似,由hashkey、sortkey、value组成。但业务数据隐含有地理信息,比如value中包含有经纬度(latitude,longitude),需要提供API进行GEO特性的支持,比如给定一个中心点坐标和一个半径,查找这个范围内的所有数据;给定两条数据的hashkey和sortkey,求这两条数据地理上的距离。
+用户数据存储在 Pegasus 中,由 hashkey、sortkey、value 组成。但用户数据中含有地理信息,比如 value 中包含有经纬度,需要 
Pegasus 提供 API 进行 GEO 特性的支持。比如给定一个中心点坐标和一个半径,查找这个范围内的所有数据;给定两条数据的 hashkey 和 
sortkey,求这两条数据地理上的距离等。
 
-pegasus的GEO(Geographic)支持使用了[S2](https://github.com/google/s2geometry)库, 
主要利用其中将二维地理坐标(经纬度)与一维编码的相互转换、基于圆形的范围查询、Hilbert曲线规则等特性。在Pegasus中如何充分利用S2的这些特性,并结合Pegasus的数据分布、数据存储特性,是本文的阐述重点。
+Pegasus 的 GEO (Geographic) 支持使用了 [S2](https://github.com/google/s2geometry) 库, 
主要用于将二维地理坐标(经度 + 纬度)与一维编码的相互转换、基于圆形的范围查询、Hilbert 曲线规则等特性。
 
-关于S2的实现原理细节请参考[S2官网](http://s2geometry.io/)
+本文将说明在 Pegasus 中是如何充分利用 S2 的特性,并结合 Pegasus 的数据分布与数据存储特性,来支持 GEO 特性的。
+
+关于 S2 的实现原理请参考 [S2官网](http://s2geometry.io/)。
 
 ## 坐标转换
 
-在S2中,可以把二维经纬度编码成一维编码,一维编码由两部分组成:立方体面、平面坐标编码,比如:
+在 S2 中,可以把二维经纬度编码成一维编码,一维编码由两部分组成:立方体面、平面坐标编码,比如:
 
-经纬度(116.334441,40.030202)的编码是:`1/223320022232200331010110113301`(32位),在S2中称为cellid。
+经纬度(116.334441, 40.030202)的编码是:`1/223320022232200331010110113301`(总共32位),这个编码在 
S2 中称为 **CellId**。
 
-其中,首位的`1`代表地球立方体投影的面索引,索引范围是0~5,如下图所示:
+其中:
+- 首位的`1`代表地球立方体投影的面索引,索引范围是0~5,如下图所示:
 
 ![geo_faces.png](/assets/images/geo_faces.png){:class="img-responsive"}
-
-`/`是分隔符
-
-`223320022232200331010110113301`(30位)是经纬度坐标经过一系列转换得到的编码,具体转换过程这里不详细描述。需要指出的是,这是一个名为Hilbert曲线编码,它最大的特点是具有稳定性、连续性。
+- `/`是分隔符
+- 
`223320022232200331010110113301`(30位),是经纬度坐标经过一系列转换得到的编码,具体转换过程这里不详细描述。需要指出的是,这是一个名为
 Hilbert 曲线编码,它最大的特点是具有稳定性、连续性。
 
 ![hilbert.png](/assets/images/hilbert.png){:class="img-responsive"}
 
-编码由前往后按层进行,完整编码是前缀编码的子区域,每个父区域由4个子区域组成,比如`00`,`01`,`02`,`03`是`0`的子区域,且前者的区域范围的并集就是后者的区域范围。最多有30层,每层都有相应的cellid集合,高层cell是底层cell的父区域,高层cellid是底层cellid的前缀。
-
-编码可以看作是一个4进制的数值编码,同时**在数值上连续的值,在地理位置上也是连续的**。
+S2 中的 Hilbert 曲线编码:
+- 编码可以看作是一个4进制的数值编码
+- 编码由左往右按层进行,最多30层
+- 一个编码代表地理上的一个方块区域,编码越长,区域越小
+- 
完整编码是前缀编码的子区域,每个父区域由4个子区域组成,比如`00`,`01`,`02`,`03`是`0`的子区域,且前者的区域范围的并集就是后者的区域范围
+- 在数值上连续的值,在地理位置上也是连续的,比如`00`和`01`的区域范围是相邻的,`0122`和`0123`的区域范围也是相邻的
 
 ## 编码精度
 
-S2中的Hilbert曲线编码由30位组成,每一位代表一层划分。下表是各层单个cell的面积和cell个数。
+S2 中的 Hilbert 曲线编码由30位组成,每一位代表一层划分。下表是各层单个 cell 的面积和 cell 个数。
 
 | **level** | **min area** | **max area** | **average area** | **units** | 
**Number of cells** |
-| --------- | ------------ | ------------ | ---------------- | --------- | 
------------------- |
-| 00        | 85011012.19  | 85011012.19  | 85011012.19      | km^2    | 6     
              |
-| 01        | 21252753.05  | 21252753.05  | 21252753.05      | km^2    | 24    
              |
-| 02        | 4919708.23   | 6026521.16   | 5313188.26       | km^2    | 96    
              |
-| 03        | 1055377.48   | 1646455.50   | 1328297.07       | km^2    | 384   
              |
-| 04        | 231564.06    | 413918.15    | 332074.27        | km^2    | 1536  
              |
-| 05        | 53798.67     | 104297.91    | 83018.57         | km^2    | 6K    
              |
-| 06        | 12948.81     | 26113.30     | 20754.64         | km^2    | 24K   
              |
-| 07        | 3175.44      | 6529.09      | 5188.66          | km^2    | 98K   
              |
-| 08        | 786.20       | 1632.45      | 1297.17          | km^2    | 393K  
              |
-| 09        | 195.59       | 408.12       | 324.29           | km^2    | 1573K 
              |
-| 10        | 48.78        | 102.03       | 81.07            | km^2    | 6M    
              |
-| 11        | 12.18        | 25.51        | 20.27            | km^2    | 25M   
              |
-| 12        | 3.04         | 6.38         | 5.07             | km^2    | 100M  
              |
-| 13        | 0.76         | 1.59         | 1.27             | km^2    | 402M  
              |
-| 14        | 0.19         | 0.40         | 0.32             | km^2    | 1610M 
              |
-| 15        | 47520.30     | 99638.93     | 79172.67         | m^2     | 6B    
              |
-| 16        | 11880.08     | 24909.73     | 19793.17         | m^2     | 25B   
              |
-| 17        | 2970.02      | 6227.43      | 4948.29          | m^2     | 103B  
              |
-| 18        | 742.50       | 1556.86      | 1237.07          | m^2     | 412B  
              |
-| 19        | 185.63       | 389.21       | 309.27           | m^2     | 1649B 
              |
-| 20        | 46.41        | 97.30        | 77.32            | m^2     | 7T    
              |
-| 21        | 11.60        | 24.33        | 19.33            | m^2     | 26T   
              |
-| 22        | 2.90         | 6.08         | 4.83             | m^2     | 105T  
              |
-| 23        | 0.73         | 1.52         | 1.21             | m^2     | 422T  
              |
-| 24        | 0.18         | 0.38         | 0.30             | m^2     | 1689T 
              |
-| 25        | 453.19       | 950.23       | 755.05           | cm^2    | 7e15  
              |
-| 26        | 113.30       | 237.56       | 188.76           | cm^2    | 27e15 
              |
-| 27        | 28.32        | 59.39        | 47.19            | cm^2    | 
108e15              |
-| 28        | 7.08         | 14.85        | 11.80            | cm^2    | 
432e15              |
-| 29        | 1.77         | 3.71         | 2.95             | cm^2    | 
1729e15             |
-| 30        | 0.44         | 0.93         | 0.74             | cm^2    | 7e18  
              |
-
+|-----------|--------------|--------------|------------------|-----------|---------------------|
+| 00        | 85011012.19  | 85011012.19  | 85011012.19      | km^2      | 6   
                |
+| 01        | 21252753.05  | 21252753.05  | 21252753.05      | km^2      | 24  
                |
+| 02        | 4919708.23   | 6026521.16   | 5313188.26       | km^2      | 96  
                |
+| 03        | 1055377.48   | 1646455.50   | 1328297.07       | km^2      | 384 
                |
+| 04        | 231564.06    | 413918.15    | 332074.27        | km^2      | 
1536                |
+| 05        | 53798.67     | 104297.91    | 83018.57         | km^2      | 6K  
                |
+| 06        | 12948.81     | 26113.30     | 20754.64         | km^2      | 24K 
                |
+| 07        | 3175.44      | 6529.09      | 5188.66          | km^2      | 98K 
                |
+| 08        | 786.20       | 1632.45      | 1297.17          | km^2      | 
393K                |
+| 09        | 195.59       | 408.12       | 324.29           | km^2      | 
1573K               |
+| 10        | 48.78        | 102.03       | 81.07            | km^2      | 6M  
                |
+| 11        | 12.18        | 25.51        | 20.27            | km^2      | 25M 
                |
+| 12        | 3.04         | 6.38         | 5.07             | km^2      | 
100M                |
+| 13        | 0.76         | 1.59         | 1.27             | km^2      | 
402M                |
+| 14        | 0.19         | 0.40         | 0.32             | km^2      | 
1610M               |
+| 15        | 47520.30     | 99638.93     | 79172.67         | m^2       | 6B  
                |
+| 16        | 11880.08     | 24909.73     | 19793.17         | m^2       | 25B 
                |
+| 17        | 2970.02      | 6227.43      | 4948.29          | m^2       | 
103B                |
+| 18        | 742.50       | 1556.86      | 1237.07          | m^2       | 
412B                |
+| 19        | 185.63       | 389.21       | 309.27           | m^2       | 
1649B               |
+| 20        | 46.41        | 97.30        | 77.32            | m^2       | 7T  
                |
+| 21        | 11.60        | 24.33        | 19.33            | m^2       | 26T 
                |
+| 22        | 2.90         | 6.08         | 4.83             | m^2       | 
105T                |
+| 23        | 0.73         | 1.52         | 1.21             | m^2       | 
422T                |
+| 24        | 0.18         | 0.38         | 0.30             | m^2       | 
1689T               |
+| 25        | 453.19       | 950.23       | 755.05           | cm^2      | 
7e15                |
+| 26        | 113.30       | 237.56       | 188.76           | cm^2      | 
27e15               |
+| 27        | 28.32        | 59.39        | 47.19            | cm^2      | 
108e15              |
+| 28        | 7.08         | 14.85        | 11.80            | cm^2      | 
432e15              |
+| 29        | 1.77         | 3.71         | 2.95             | cm^2      | 
1729e15             |
+| 30        | 0.44         | 0.93         | 0.74             | cm^2      | 
7e18                |
 
 
 ## 数据存储
 
-在Pegasus中,数据存储的key是hashkey+sortkey: 
hashkey用于数据partition,同一hashkey的数据存储在同一replica 
server下的一块或多块(由rocksdb实际存储的状态决定:数据随机写入后,同一hashkey下连续的sortkey空间可能分布在多个不连续的sst文件中,进行full
 compact后,会分布在连续sst的内)连续区域; sortkey用于在这块(或多块)区域中做数据排序的依据。
+在 Pegasus 中,数据存储的 key 是 hashkey + sortkey:hashkey 用于确定数据所处的 partition,同一 
hashkey 的数据存储在同一 Replica Server 的一块逻辑连续的区域中,sortkey 用于在这块区域中做数据排序。
 
-经纬度经过坐标转换得到一维编码(字符串)后,就可以把这个一维编码作为key存储起来做**GEO索引数据**了,这里需要将这个一维编码拆分成hashkey和sortkey两部分,可以根据实际的业务场景采取不同的划分策略。
+经纬度经过坐标转换得到一维编码 CellId 后,就可以把这个一维编码作为 key 存储起来做**GEO索引数据**了,Pegasus 将这个一维编码拆分成 
hashkey 和 sortkey 两部分,可以根据实际的用户场景采取不同的位数划分策略。
 
-GEO索引数据独立于原始数据,两类数据存储在不同的table内,通过[geo_client](https://github.com/apache/incubator-pegasus/blob/master/src/geo/lib/geo_client.h)做数据同步,同时支持原生Pegasus
 API和GEO API访问。
+GEO 索引数据独立于原始数据,两类数据存储在不同的 Pegasus 表中,通过 [GEO 
Client](https://github.com/apache/incubator-pegasus/blob/master/src/geo/lib/geo_client.h)
 做数据同步,同时支持原生 Pegasus API 和 GEO API 的访问。
 
-下面讨论GEO索引数据的构造方式。
+所以,在使用 Pegasus GEO 特性时,需要创建两个 Pegasus 表,一个是原始表,用于存储用户写入的原始数据,一个是 GEO 索引表,用于存储 
GEO Client 自动转换原始数据生成的 GEO 索引数据。
 
 ### hashkey
 
-hashkey直接由一维编码的前缀构成。比如在我们的LBS业务场景中,范围查询都是集中在10km半径内的圆形范围,实际测试结果是将hashkey长度定为`14`(1位face,1位分隔符`/`,12位Hilbert编码)能取得更好的性能。
+hashkey 直接由一维编码的前缀构成。比如在一个用户场景中,范围查询都是集中在 10km 半径内的圆形范围,实际测试结果是将 hashkey 
长度定为`14`(1位face,1位分隔符`/`,12位Hilbert编码)能取得更好的性能。
 
-> `最小搜索层`为12
+> 那么,最小搜索层就为12
 
 ```
-               cellid
-|--------------32 bytes-------------|
-|---14 bytes----|
+              CellId
+|1/223320022232..................|
+|-------------32 bytes-----------|
+|---14 bytes--|
     hashkey
 ```
 
 ### sortkey
 
-为了满足不同半径范围、不同精度的查询,我们把cellid剩下的18位全部放到sortkey中(这并不会给底层存储带来多少压力),这可以在应用层保持比较高的灵活性,而不用修改底层的数据。在进行较大范围的临近查询时,取更少的sortkey位数(对应的cellid更短)进行数据查询;进行较小范围的临近查询或点查询时,取更多的sortkey位数(对应的cellid更长)进行数据查询。
+为了满足不同半径范围、不同精度的查询,我们把 CellId 剩下的 18 位全部放到 sortkey 中。
+- 在进行较大范围的临近查询时,取更少的 sortkey 位数(对应的 CellId 更短)作为前缀,进行数据 scan 查询,这样可以减少数据 scan 
的次数
+- 在进行较小范围的临近查询或点查询时,取更多的 sortkey 位数(对应的 CellId 更长)作为前缀,进行数据 scan 查询,这样可以减少数据 
scan 的范围
 
-尽管在30层时,cell的面积已经足够小(<1cm^2),但仍有可能两条数据落在同一个cell里,所以需要区分不同的数据。这里,将原始数据的hashkey和sortkey联合起来,并追加在上述sortkey之后。
+这可以在不修改底层存储数据的前提下,让应用层保持比较高的灵活性。
 
-                   cellid
-    |--------------32 bytes-------------|
-    |---14 bytes---||-----18 bytes------||--原始hashkey--||--原始sortkey--|
-    |--GEO hashkey-||----------------------GEO sortkey-------------------|
+> 查询相同地理区域内(例如一个圆形区域)的数据时,使用短 CellId 查询数据查询的范围更大,查询的次数更少,但得到的在区域外的无用数据更多。而使用长 
CellId 查询数据查询的范围更小,得到的在区域外的无用数据更少,但查询的次数更多
+> 
+> 参考:[S2 coverings](http://s2geometry.io/devguide/examples/coverings)
 
+尽管在第30层时,cell 的面积已经足够小(<1cm^2),但仍有可能两条数据落在同一个 cell 里,所以需要在 CellId 编码的基础上,解决 
key 冲突问题。Pegasus 将**原始表**的 hashkey 和 sortkey 联合起来,追加在 GEO 表的 sortkey 之后。
 
-> 
在相同地理范围内进行数据查询时,使用短cellid查询数据查询的范围大,查询的次数更少,但得到的在区域外的无用数据更多,反之亦然---这需要在查询次数与查询到的有用数据之间做权衡。
+```
+               CellId
+|1/223320022232200331010110113301|
+|-------------32 bytes-----------|
+|---14 bytes--||-----18 bytes----||--原始hashkey--||--原始sortkey--|
+|-GEO hashkey-||-------------------GEO sortkey-------------------|
+```
 
 ### value
 
-GEO 
API的value必须能够解析出经纬度,具体的解析方式参考[自定义extrator](https://pegasus.apache.org/api/geo#%E8%87%AA%E5%AE%9A%E4%B9%89extrator)。
+使用 GEO 特性所存储的 value 
必须能够解析出经纬度,具体的解析方式参考[自定义extrator](/api/geo#%E8%87%AA%E5%AE%9A%E4%B9%89extrator)。
 
-GEO索引数据的value跟原始数据的value完全相同。这里会存在一份冗余,但通常在相对廉价的磁盘存储介质上,这是可以接受的。
+GEO 索引表的 value 跟原始表的 value 完全相同。这里会存在一份冗余数据,使用空间换时间的方式避免二次索引。
 
-> 我们建议业务层在使用GEO API时value只存储小数据,大数据建议采用二次索引的方式。
+> 如果确实有在 GEO 的单条 value 中存储较大数据的需求,又想节省磁盘空间,可以手动实现二次索引,即在 GEO value 中存储二级索引的 
key,再在另外的表中存储真实的大 value。
 
 ## 数据更新
 
 ### set
 
-`set`操作会同时更新两个table的数据: Pegasus原始数据和GEO索引数据(数据构造方式如上所述)。
+`set` 操作会同时更新上述两个表的数据,即 Pegasus 原始表数据和 GEO 索引表数据,数据构造方式也如上所述。
 
-> `set`操作的hashkey, sortkey是业务自己的格式,使用GEO API时并不做约束, 只是在geo 
client转存GEO索引数据时,会自动做如上所述的编码转换。
+`set`操作的 hashkey,sortkey 是用户自己的格式,使用 GEO API 时并不做约束。两个表的数据转储对用户是透明的,由 GEO 
Client 自动完成。
 
-> 使用Redis API时, 参考 [GEO API](https://pegasus.apache.org/api/redis#geo-api)。
+使用 Redis GEO API 时, 参考 [GEO API](/api/redis#geo-api)。
 
-> 
实现上,`set`会首先尝试`get`出已有的数据,并将已有数据的GEO索引数据清理掉后,再写入新数据。因为新老数据的索引数据hashkey+sortkey可能不一样(即新老value根据extractor解析得到的经纬度不一样),若不清理,在进行地理搜索时将会搜索到脏数据。
+在 Pegasus 实现中,`set`操作会首先尝试读取出已有的数据,如果数据不存在,则直接向两个表中写入数据。如果数据已存在,会先将老的 GEO 
索引数据清理掉后,再写入新数据。因为新老数据的索引数据 <hashkey, sortkey> 可能是不一样的(即新老 value 根据 extractor 
解析得到的经纬度不一样),若不清理,GEO 索引表中将存在垃圾数据,造成磁盘空间的浪费,也会在进行地理范围查询时(即`GEORADIUS`)查到脏数据。
 
 ### del
 
-`del`操作也会同时删除两个table的数据,原理同上。
+`del`操作会同时删除两个表的数据,原理同上。
 
 ## 数据查询
 
 ### 思路
 
-直观地,集合中总的cell数量尽可能少,但同时单个cell面积尽可能小。比如:
+地理范围查询会转换成 Pegasus 的多次 scan 操作,一次 scan 对应为一个 CellId 范围内的所有数据扫描。 
要想获得更高的性能,就需要减少 scan 的总次数和单次 scan 的数据量,也就是需要减少总的 CellId 数量和单个 CellId 的面积。
+
+比如,在做如下红色圆圈的范围查询时,可以采取蓝色方框的 CellId 查询集合:
 
 ![s2_cap_1.png](/assets/images/s2_cap_1.png){:class="img-responsive"}
 
-虽然这样的结果更精确,但在实际测试中发现当参与计算的cell层级越大时,cellid的数量就越多,带来的client-server 
RPC次数更多,整个API消耗更大、延迟就越高。同时,在真实的应用场景中,太小的cell意义不大(没有数据)。
+虽然这样的结果更精确,但参与计算的 CellId 的数量更多,带来的 client-server RPC 
次数更多,网络开销更大,延迟更高。此外,在真实的应用场景中,太小的 CellId 可能并没有数据,但依然会消耗一次 RPC。
 
-所以,在当前的Pegasus实现中,只联合使用两层cell,`最大搜索层`和`最小搜索层`, 以12层和16层为例:
+所以,在当前的 Pegasus 实现中,只联合使用两层 cell,`最小搜索层`和`最大搜索层`, 以 12 层和 16 层为例,得到的 CellId 
查询集合如蓝色方框所示:
 
 ![s2_cap_2.png](/assets/images/s2_cap_2.png){:class="img-responsive"}
 
 ### 查询流程
 
-以search_radial为例,此API的意义是给定点和半径,求出该圆形区域内的所有数据。
+以`search_radial`为例,此 API 的意义是给定点和半径,查询出该圆形区域内的所有数据。
 
 > 这里我们只讨论圆形区域的数据查询,其他的比如多边形区域的思想是类似的。
 
-需利用S2提供的查询覆盖指定区域的cellid集合的API:
+需利用 S2 提供的查询覆盖指定区域的 CellId 集合的 API:
 
 ```
 // Returns an S2CellUnion that covers the given region and satisfies the 
current options.
 S2CellUnion GetCovering(const S2Region& region);
 ```
 
-> `search_radial`API有两个重载函数,一个是输入经纬度,一个是输入hashky+sortkey,后者是通过key取到经纬度再转调前者。
+> `search_radial` API 有两个重载函数,一个是输入经纬度,一个是输入 hashky + sortkey,后者是通过 key 取到 
value 中的经纬度再转调前者。
 
 查询流程如下:
 
-1. 根据经纬度、半径,求出S2Cap圆形区域`C`
-2. 根据圆形区域、指定的`最小搜索层`,通过`GetCovering`,求出在`最小搜索层`上的cellid集合
-3. 遍历这些cellid,判断cellid区域跟圆形区域`C`的关系
-   1. 全覆盖:取该cellid的所有数据
-   2. 半覆盖:将该cellid按`最大搜索层`继续拆份, 判断拆分后的sub_cellid区域与圆形区域`C`的关系
-      1. 相交:取该sub_cellid的所有数据
-      2. 不相交:排除
+1. 根据经纬度、半径,求出 S2Cap 圆形区域`C`
+2. 根据圆形区域、指定的`最小搜索层`,通过`GetCovering`,求出在`最小搜索层`上的 CellId 集合
+3. 遍历这些 CellId,判断 CellId 区域跟圆形区域`C`的关系
+   1. 全覆盖:取该 CellId 内的所有数据
+   2. 半覆盖:将该 CellId 按`最大搜索层`继续拆分,判断拆分后的 sub_CellId 区域与圆形区域`C`的关系
+      1. 覆盖/相交:取该 sub_CellId 的所有数据
+      2. 不相交:丢弃
 
 > `最小搜索层`,`最大搜索层`的配置参考后文。
+> `最小搜索层`的 CellId 长度确定 GEO 索引表的 hashkey 长度。
 
-取一个cellid的所有数据时,会根据上文的key构造规则,构造一对包含这个cellid所有数据的`start_sortkey`,`stop_sortkey`,再使用Pegasus的`scan`接口进行数据搜索。
-
-- 对于`3.1`步取到的cellid,它的长度即是hashkey的长度,它也就是hashkey,调用`scan(cellid, '"', "")`搜索数据
-  - 比如,一个12层cell `1/223320022232`被区域完全覆盖,则我们`scan("1/223320022232", "", "")`。
-- 对于`3.2.1`步取到的sub_cellid,hashkey是它的前缀,调用`scan(sub_cellid[0:hashkey_len], 
sub_cellid[hashkey_len:], sub_cellid[hashkey_len:])`搜索数据
-  - 比如,一个12层cell 
`1/223320022232`的子区域`0001`,`0002`,`0003`,`0100`才跟目标区域相交时,则我们`scan("1/223320022232",
 "0001", "0003")`、`scan("1/223320022232", "0100", "0100")`。
+取一个 CellId 的所有数据时,会根据上文的 key 构造规则,构造一对包含这个 CellId 
所有数据的`start_sortkey`,`stop_sortkey`,再使用Pegasus的`scan`接口进行数据搜索。
 
-> 
此处还有一个根据Hilbert曲线实现的一个优化,具体参见[代码](https://github.com/apache/incubator-pegasus/blob/master/src/geo/lib/geo_client.cpp)
+- 对于`3.1`步取到的`最小搜索层` CellId 的编码,它也就是 GEO 索引表中的 hashkey,调用`scan(CellId, "", 
"")`查询所有数据
+  - 比如,一个 12 层的 cell `1/223320022232`被区域完全覆盖,则调用`scan("1/223320022232", "", 
"")`查询所有数据
+- 对于`3.2.1`步取到的 sub_CellId 集合,hashkey 是它的前缀,调用`scan(sub_CellId_common_prefix, 
sub_CellId1, sub_CellId2)`搜索数据
+  - 其中,sub_CellId_common_prefix 是 sub_CellId 集合的公共前缀,长度是 hashkey 
的长度。sub_CellId1 和 sub_CellId2 之间连续的所有 sub_CellId 都在集合中,字符串长度是`最大搜索层`减`最小搜索层`的长度
+  - 比如,一个12层的 cell 
`1/223320022232`的子区域`0001`,`0002`,`0003`,`0100`才跟目标区域相交时,则调用`scan("1/223320022232",
 "0001", "0003")`、`scan("1/223320022232", "0100", "0100")`
 
 得到`scan`的结果后,还需处理:
 
-- 计算距离:因为cellid可能只与输入区域部分重合,该点若在区域外, 需去除
+- 计算距离:因为 CellId 可能只与输入区域部分重合,该点若在区域外,需丢弃
 - 排序:当有升序/降序要求时
 
 ### 灵活性
 
-由于我们存储了完整的30层cellid,所以在实际使用中,可以按照自己的地理数据密度、延迟要求等情况调整API的的`最大搜索层`。
+由于我们存储了完整的 30 层 CellId,所以在实际使用中,可以按照自己的地理数据密度、网络 IO、磁盘 IO等情况调整 API 的`最大搜索层`。
 
-> 默认为`16`。
+> `最大搜索层`默认为`16`。
 
 #### API方式
 
@@ -209,7 +223,9 @@ max_level = 16
 
 ### 不变性
 
-修改hashkey长度需要修改配置文件,但需注意:hashkey一旦确定,数据写入后改配置便不可修改,因为数据已按这个hashkey长度规则固化下来。
+由于`最小搜索层`确定了 hashkey 的长度,数据一旦写入 Pegasus 后,`最小搜索层`便不可修改了,因为数据已按这个 hashkey 
长度规则固化下来。
+
+若要修改,需要重建数据。
 
 > 默认为`12`。
 
@@ -221,19 +237,21 @@ min_level = 12
 
 ## 自定义extrator
 
-目前Pegasus支持从固定格式的value中解析经纬度。经纬度以字符串形式嵌入在value中,以`|`分割, 
比如:`.*|115.886447|41.269031|.*`,他们的索引由配置文件中的`latitude_index`和`longitude_index`确定。
+目前 Pegasus 支持从固定格式的 value 中解析出经纬度。经纬度以字符串形式嵌入在 value 中,以`|`分割。
+
+比如:`.*|115.886447|41.269031|.*`,经纬在 value 
中的索引由配置文件中的`latitude_index`和`longitude_index`确定。
 
-## API & redis proxy
+## API & Redis Proxy
 
-Pegasus GEO特性的使用有两种方式,一是直接使用C++ geo client;二是使用redis proxy。
+Pegasus GEO 特性的使用有两种方式,一是直接使用 C++ GEO Client,二是使用 Redis Proxy。
 
-[C++ geo 
client代码](https://github.com/apache/incubator-pegasus/blob/master/src/geo/lib/geo_client.h)中有详细的API说明,这里不再赘述。
+[C++ GEO 
client代码](https://github.com/apache/incubator-pegasus/blob/master/src/geo/lib/geo_client.h)中有详细的
 API 说明,这里不再赘述。
 
 ## 配置文件
 
-redis proxy的使用请参考[Redis适配](redis)。
+Redis Proxy 的使用请参考[Redis适配](redis)。
 
-GEO API添加的配置文件如下:
+GEO API 添加的配置文件如下:
 
 ```
 [geo_client.lib]
@@ -248,17 +266,15 @@ longitude_index = 4
 
 ## 数据导入
 
-有的使用场景是业务已经有普通的KV数据,需要根据这份已有的KV数据转换成如上述的数据格式,我们可以使用shell工具里的`copy_data`功能来实现。比如:
+有的使用场景是用户已经有普通的 KV 数据,需要根据这份已有的 KV 数据转换成如上述的数据格式,我们可以使用 shell 
工具里的[copy_data](/docs/tools/shell/#copy_data)功能来实现。比如:
+
+在进行`copy_data`操作之前,目标集群以及两个目标表(例如,原始数据表`temp`,GEO 索引数据表 `temp_geo`)都需要提前创建好。
 
 ```
 copy_data -c target_cluster -a temp -g
 ```
 
-此时目标集群是`target_cluster`,目标表是`temp`,他存储上述的普通数据,目标GEO索引数据表是`temp_geo`,他存储上述的GEO索引数据。
-
-在进行`copy_data`操作之前,目标集群以及两个目标表都需要提前创建好。
-
-数据导入完成后就可以搭建`redis_proxy`了,具体的说明参考[redis适配](redis),需要注意的是配置项:
+数据导入完成后就可以搭建 Redis Proxy 了,具体的说明参考[Redis适配](redis),需要注意的是配置项:
 
 ```
 [apps.proxy]
@@ -266,11 +282,11 @@ copy_data -c target_cluster -a temp -g
 arguments = redis_cluster temp temp_geo
 ```
 
-## benchmark
+## Benchmark
 
 ### 测试环境
 
-机器配置:
+服务器配置:
 
 - CPU:E5-2620v3 *2
 - 内存:128GB
@@ -279,9 +295,9 @@ arguments = redis_cluster temp temp_geo
 
 集群配置:
 
-- 节点数:5个replica server节点(使用v1.9.2版本)
-- 测试表的Partition数:128个
-- 单条数据大小:120字节
+- 节点数:5 个 Replica Server 节点(使用 v1.9.2 版本)
+- 测试表的 Partition 数:128
+- 单条数据大小:120 字节
 
 针对接口:
 
@@ -296,23 +312,19 @@ void async_search_radial(double lat_degrees,
 ```
 
 传递参数:
-
-lat_degrees、lng_degrees:每次都选取北京五环内的随机点
-
-radius_m:如下表第一列,单位米
-
-count:-1,表示不限定结果数量
-
-sort_type:不排序
+- lat_degrees、lng_degrees:每次都选取北京五环内的随机点
+- radius_m:如下表第一列,单位米
+- count:-1,表示不限定结果数量
+- sort_type:不排序
 
 ### 测试结果
 
-| 半径(m) | P50(ms)     | P75(ms)     | P99(ms)     | P99.9(ms)   | 平均结果条数 | 
单节点QPS |
-| ------- | ----------- | ----------- | ----------- | ----------- | 
------------ | --------- |
-| 50      | 1.63071622  | 1.84607433  | 4.04545455  | 6.28        | 9.4608     
  | 740.287   |
-| 100     | 1.76        | 2.33614794  | 5.4         | 6.45319149  | 38.0296    
  | 656.66    |
-| 200     | 2.41017042  | 3.31062092  | 6.41781609  | 9.60588235  | 154.3682   
  | 536.624   |
-| 300     | 3.30833333  | 4.21979167  | 9.4310559   | 18          | 350.9676   
  | 434.491   |
-| 500     | 5.07763975  | 6.84964682  | 16.84931507 | 21.78082192 | 986.0826   
  | 347.231   |
-| 1000    | 12.28164727 | 18.70972532 | 43.18181818 | 57.049698   | 3947.5294  
  | 204.23    |
-| 2000    | 35.78666667 | 54.7300885  | 108.7331378 | 148.616578  | 15674.1198 
  | 98.7633   |
+| Radius(m) | P50(ms)     | P75(ms)     | P99(ms)     | P99.9(ms)   | Avg 
result count | QPS per node |
+|-----------|-------------|-------------|-------------|-------------|------------------|--------------|
+| 50        | 1.63071622  | 1.84607433  | 4.04545455  | 6.28        | 9.4608   
        | 740.287      |
+| 100       | 1.76        | 2.33614794  | 5.4         | 6.45319149  | 38.0296  
        | 656.66       |
+| 200       | 2.41017042  | 3.31062092  | 6.41781609  | 9.60588235  | 154.3682 
        | 536.624      |
+| 300       | 3.30833333  | 4.21979167  | 9.4310559   | 18          | 350.9676 
        | 434.491      |
+| 500       | 5.07763975  | 6.84964682  | 16.84931507 | 21.78082192 | 986.0826 
        | 347.231      |
+| 1000      | 12.28164727 | 18.70972532 | 43.18181818 | 57.049698   | 
3947.5294        | 204.23       |
+| 2000      | 35.78666667 | 54.7300885  | 108.7331378 | 148.616578  | 
15674.1198       | 98.7633      |


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to