MongoDB:根据给定区域和最大点的地理位置聚类文档?

Dan*_*anM 6 geolocation mongodb geohashing node.js leaflet

我正在尝试开发一个基于地图的可视化,其中包含一个子群体的"热图",基于包含以下文档的MongoDB集合:

{
    "PlaceName" : "Boston",
    "Location" : {
        "type" : "Point",
        "coordinates" : [ 42.358056, -71.063611 ]
    },
    "Subpopulations": {
        "Age": { 
                "0_4" : 37122,
                "6_11" : 33167,
                "12_17" : 35464,
                "18_24" : 130885,
                "25_34" : 127058,
                "34_44" : 79092,
                "45_54" : 72076,
                "55_64" : 59766,
                "65_74" : 33997,
                "75_84" : 20219,
                "85_" : 9057
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

数据库中有数十万个单独的位置.它们重叠 - 即"纽约市"和"曼哈顿"不会有两个单独的条目.

目标是使用Leaflet.js和一些插件来呈现此数据的各种可视化.Leaflet非常擅长聚类数据客户端 - 所以如果我通过密度值传递了千个位置,它可以通过处理所有单个值来渲染相关区域的热图.

问题是,我说缩小地图以显示整个世界.如果不是不可能的话,将所有数据发送到客户端并使其足够快地处理该信息以实现平滑可视化将是非常低效的.

所以我需要做的是自动集群数据服务器端,我希望可以在MongoDB查询中完成.我已经读过,geohashing可能是确定哪些点属于哪些集群的一个很好的起点,但我确信有人之前已经完成了这个问题并且可能有更好的洞察力.理想情况下,我想向我的node.js脚本发送一个查询,如下所示:

http://myserver.com/popdata?top=42.48&left=-80.57&bottom=37.42&right=-62.55&stat=Age&value=6_11
Run Code Online (Sandbox Code Playgroud)

这将根据要返回的数据点的最大数量或沿着这些线的某些内容,根据指定地理区域内有多少个点来确定聚类需要多少粒度; 它将返回如下数据:

[
    { "clusterlocation": [ 42.304, -72.622 ], "total_age_6_11": 59042 },
    { "clusterlocation": [ 36.255, -64.124 ], "total_age_6_11": 7941 },
    { "clusterlocation": [ 40.425, -70.693 ], "total_age_6_11": 90257 },
    { "clusterlocation": [ 39.773, -67.992 ], "total_age_6_11": 102752 },
    ...
]
Run Code Online (Sandbox Code Playgroud)

...其中"clusterlocation"类似于集群中所有文档位置的平均值,"total_age_6_11"是"Subpopulations.Age.6_11"的文档值的总和.

这是我可以纯粹在Mongo查询中做的事吗?是否有"经过试验和测试"的方法来做得好?

Dhr*_*hak 4

即使您在运行时执行此查询,它也会效率低下,并且速度不快,无法被视为良好的用户界面。我建议您预先生成特定大小的簇,并将它们与原始文档一起存储在您当前的集合中。具体方法如下:

  • 每个文档将存储一个附加字段(我们称之为 geolevel ),它将表示它的实体有多大或多小。您的基础文档将具有 geolevel=1 :

    {
        "PlaceName" : "Boston",
        "Location" : {
            "type" : "Point",
            "coordinates" : [ 42.358056, -71.063611 ]
        },
        "Subpopulations": {
            "Age": { 
                    "0_4" : 37122,
                    "6_11" : 33167,
                    "12_17" : 35464,
                    "18_24" : 130885,
                    "25_34" : 127058,
                    "34_44" : 79092,
                    "45_54" : 72076,
                    "55_64" : 59766,
                    "65_74" : 33997,
                    "75_84" : 20219,
                    "85_" : 9057
            }
        },
        "geolevel":1  // added geolevel
    }
    
    Run Code Online (Sandbox Code Playgroud)
    • 您可以对数据库运行处理,为集群和多个级别预先生成类似文档。例如,geolevel:2 将是半径 250 公里内的几个城市的集群,geolevel:3 将是 geolevel:2 集群的集群。

    • 您还可以存储一个字段,例如memberids存储每个集群中子节点的 id。这可能是必要的,以避免实体进入两个相邻的集群,它可以分配给任何一个相邻的集群,并且您的可视化仍然可以正常工作。geolevel:2 集群文档如下所示:

       {
          "PlaceName" : "cluster_sdfs34535",  // The id can be generated from hash like sha of a list of all children ids.
          "Location" : {  // center of the cluster
              "type" : "Point",
              "coordinates" : [ 42.358056, -71.063611 ]
          },
          "Subpopulations": { // total population of the cluster
              "Age": { 
                      "0_4" : 371220,
                      "6_11" : 331670,
                      "12_17" : 354640,
                      "18_24" : 1308850,
                      "25_34" : 1270580,
                      "34_44" : 790920,
                      "45_54" : 720760,
                      "55_64" : 597660,
                      "65_74" : 339970,
                      "75_84" : 202190,
                      "85_" : 90570
              }
          },
          "geolevel":2 ,
          "childs":[4,5,6,7] // ids of child documents
      }
      
      Run Code Online (Sandbox Code Playgroud)
    • 现在,您的可视化应用程序需要进行缩放级别到地理级别的映射,并基于该映射选择文档。对于城市级别可视化,您可以查询 geolevel:1 文档,当缩小到州、国家等时,您可以将 geolevel 增加到 2,3...