如何在cassandra中的两列上有效地进行范围查询?

时间:2012-10-09 21:40:55

标签: indexing cassandra range

我想将数百万个地点保存到Cassandra的ColumnFamily中,然后对这些数据进行范围查询。

例如:

属性:LocationName,纬度,经度 查询:SELECT LocationName FROM ColumnFamily WHERE latitute> 10和纬度< 20和经度> 30和经度< 40;

我应该使用哪些结构和索引,以便查询有效?

2 个答案:

答案 0 :(得分:0)

根据您在查询中所需的粒度(以及该粒度的可变性),处理此问题的一种方法是将地图切割为网格,其中所有位置都属于具有已定义纬度的网格方块内/ lon边界框。然后,您可以对网格方形ID进行初始查询,然后对这些方块内的位置进行初始查询,其表示形式如下:

GridSquareLat {
  key: [very_coarse_lat_value] {
    [square_lat_boundary]:[GridSquareIDList]
    [square_lat_boundary]:[GridSquareIDList]
  }
  ...
}

GridSquareLon {
  key: [very_coarse_lon_value] {
    [square_lon_boundary]:[GridSquareIDList]
    [square_lon_boundary]:[GridSquareIDList]
  }
  ...
}

Location {
  key: [locationID] {
    GridSquareID: [GridSquareID]  <-- put a secondary index on this col
    Lat: [exact_lat]
    Lon: [exact_lon]
    ...
  }
  ...
}

然后,您可以向Cassandra提供GridSquareLat / Lon键,表示非常粗糙的粒度lat / lon值,以及列切片范围,这将减少返回到边界内的那些方块的列。您将获得两个列表,一个是lat的网格方形ID,另一个是lon。这些列表的交集将是您范围内的网格方块。

要获取这些方块中的位置,请查询位置CF,过滤GridSquareID(使用二级索引,只要您的总网格平方数合理,这将是有效的)。您现在拥有一个合理大小的位置列表,只有几个非常有效的查询,您可以轻松地将它们缩小到您的应用程序内的确切列表。

答案 1 :(得分:0)

让我们假装你将成长为数十亿(我将在下面做出数百万的案例)。如果你在cassandra上使用像PlayOrm这样的东西(或者你可以自己做而不是使用PlayOrm),你需要按某种方式进行分区。假设您选择按经度划分,以便介于&gt; = 20和&lt;之间的任何值。 30在分区20中并且在&gt; = 30和&lt; 30之间。 40在分区30中。然后在PlayOrm中,您使用它的可伸缩SQL来编写您编写的相同查询,但是您需要查询正确的分区,在某些情况下,这些分区将是多个分区,除非您限制结果集大小... < / p>

在PlayOrm或您的数据模型中,它看起来像(不需要其他表格)

Location {
  key: [locationID] {
    LonBottom: [partitionKey]
    Lat: [exact_lat] <- @NoSqlIndexed
    Lon: [exact_lon] <- @NoSqlIndexed
    ...
  }
  ...
}

也就是说,如果你是数百万,你就不需要分区,所以只需删除上面的LonBottom列并不进行分区....当然,为什么要使用noSQL,因为数百万不是那么大而且RDBMS可以很容易处理数百万。

如果你想自己做,在数百万的情况下,Lat和Lon(宽行模式)有两行,它们包含lat和long的索引值来查询。对于billinos案例,每个分区会有两行,因为每个分区都有自己的索引,因为你不希望索引太大。

索引行很容易创建。它只是rowkey =“index name”,每个列名称是经度的复合名称和位置的行键。每列没有值,只是一个复合名称(这样每个列名都是唯一的。)

所以你的行可能看起来像

longindex = 32.rowkey1, 32.rowkey45, 32.rowkey56, 33.rowkey87, 33.rowkey89

其中32和33是经度,而行键指向位置。