键值存储中的反向索引和数据建模

问题描述 投票:1回答:1

我是key-value商店的新手。我的目标是使用嵌入式键值存储来保留持久数据模型。如果使用常规RDBMS设计,则数据模型包含很少的相关表。我正在检查有关为键值存储表建模的medium article。尽管本文将Level DB与Java结合使用,但我仍计划在C ++中将RocksDBFASTER与C ++一起使用。

[它使用一种方案,其中每一行的每个属性都使用一个键,如下面的示例。

$table_name:$primary_key_value:$attribute_name = $value

当用户代码确切知道要获取哪个键时,以上对于点查找很好。但是,有些情况下,例如搜索具有相同电子邮件地址的用户,搜索特定年龄以上的用户或搜索一种特定性别的用户。在搜索方案中,文章将对所有键进行线性扫描。在每次迭代中,一旦找到具有匹配模式的键,它就会检查键的模式并应用业务逻辑(检查匹配值)。

似乎,这种类型的搜索效率低下,在最坏的情况下,它需要遍历整个商店。为了解决这个问题,需要一个反向查询表。我的问题是

如何为反向查询表建模?这是车轮的重塑吗?还有其他方法吗?

一个容易想到的解决方案是为每个可索引属性设置separate ?存储,如下所示。

$table_name:$attribute_name:$value_1 = $primary_key_value 

使用这种方法,直接的问题是

如何处理此反向查询表中的冲突?因为多个$primary_key可能与同一标签相关联。

作为一种立即解决方案,可以存储多个主键的array,而不是存储单个值,如下所示。

$table_name:$attribute_name:$value_1 = [$primary_key_value_1, ... , $primary_key_value_N]

但是这种类型的建模需要用户代码从字符串中解析数组,并在多次操作后再次将其序列化为字符串(假定基础键值存储不了解数组值)。

将多个键存储为数组值是否有效?还是存在一些提供有效方法的供应商?

假定像设计那样的字符串化数组起作用,每个可索引属性必须有这样的索引。因此,这为要索引的内容和不索引的内容提供了细粒度的控制。接下来要考虑的设计决策是这些索引将存储在哪里?

索引应存储在单独的存储/文件中吗?还是实际数据属于同一存储/文件?每个属性应该有不同的商店吗?

对于这个问题,我没有任何线索,因为这两种方法都需要或多或少相同数量的I / O。但是,具有大数据文件将在磁盘上存储更多内容,而在内存中减少存储内容(因此增加I / O),而对于多个文件,将在内存中存储更多内容,从而减少页面错误。根据特定键值存储的体系结构,这种假设可能是完全错误的。同时,文件过多会成为管理复杂文件结构的问题。同样,维护索引需要事务进行插入,更新和删除操作。具有多个文件导致在多个树中进行单个更新,而具有单个文件导致在单个树中进行多个更新。

更具体地说,是否涉及多个存储/文件的交易?

不仅索引,表的一些元信息也需要与表数据一起保存。要生成新的主键(自动递增),需要先了解最后生成的行号或生成的主键,因为类似COUNT(*)的内容将无法使用。另外,由于未对所有键进行索引,因此meta信息可能包括对哪些属性进行了索引以及对哪些属性未进行索引。

如何存储每个表的元信息?

同样,元表也会出现相同的问题集。例如元应该是单独的存储/文件吗?此外,由于我们注意到并非所有属性都已建立索引,我们甚至可以决定将每一行作为JSON编码的值存储在数据存储区中,并将其与索引存储区一起保存。基础键值存储供应商将将该JSON视为字符串值,如下所示。

$table_name:data:$primary_key_value = {$attr_1_name: $attr_1_value, ..., $attr_N_name: $attr_N_value}
...
$table_name:index:$attribute_name = [$primary1, ..., $primaryN]

但是通过指向主键的索引仍然可以进行反向查找。

使用JSON编码值而不是将所有属性存储为单独的键是否有任何弊端?

到目前为止,除了强制用户使用JSON编码以及为JSON编码/解码进行一些堆分配外,我无法使用此方法找到任何缺点。

上述问题并非特定于任何特定应用。这些问题足够通用,可以与使用key-value存储的所有开发相关联。因此,有必要知道是否对车轮进行了重新发明。

问题中提到的所有问题都有事实上的标准解决方案吗?解决方案是否与问题中所述的解决方案不同?

database data-modeling key-value-store leveldb rocksdb
1个回答
0
投票

如何为反向查询表建模?这是车轮的重塑吗?还有其他方法吗?

  • 您描述的所有方法都是创建索引的有效方法。
  • 由于RocksDB不支持索引,因此它不会在RocksDB中重新发明轮子。
  • 它实际上取决于数据,通常,您需要将索引值和主键复制到另一个空间中以创建索引。

如何处理此反向查询表中的冲突?因为多个$ primary_keys可能与同一个vale相关联。

您可以使用JSON(或其他方式)序列化pk。这种方法的问题是,当pk变得非常大时(可能是也可能不是东西)。

将多个键存储为数组值是否有效?还是存在一些提供有效方法的供应商?

使用RocksDB,您将没有任何东西可以使其变得更加“轻松”。

您没有提到以下方法:

$table_name:$attribute_name:$value_1:$primary_key_value_1 = ""
$table_name:$attribute_name:$value_1:$primary_key_value_2 = ""
...

$table_name:$attribute_name:$value_1:$primary_key_value_n = ""

其中值为空。并且索引为pk的键的一部分。

索引应存储在单独的存储/文件中吗?还是实际数据属于同一存储/文件?每个属性应该有不同的商店吗?

取决于键值存储。使用rocksdb,如果需要事务,则必须坚持一个db文件。

更具体地说,是否涉及多个存储/文件的交易?

[仅Oracle Berkeley DB和WiredTiger支持该功能。

如何存储每个表的元信息?

元数据可以在数据库或代码中。

使用JSON编码值而不是将所有属性存储为单独的键是否有任何弊端?

是的,就像我上面说的那样,如果您将所有pk编码为一个值,那么当pk数量很大时,可能会导致下游问题。例如,您需要阅读整个列表才能进行分页。

问题中提到的所有问题都有事实上的标准解决方案吗?解决方案是否与问题中所述的解决方案不同?

总结:

  • 使用RocksDB,使用单个数据库文件
  • 在索引中,对键内的主键进行编码,并将值保留为空,以便能够进行分页。
© www.soinside.com 2019 - 2024. All rights reserved.