0

我有一个parenthashmap 数据结构,它有一个字符串作为键,hashmap 数据结构作为子项(猜测child1,,child2...,childN)。每个孩子都是一个简单的键值映射,有一个数字作为键,一个字符串作为值。在伪代码中:

parent['key1'] = child1;    // child1 is a hash map data structure
child1[0] = 'foo';
child[1] = 'bar';
...

我需要将此数据结构实现为数据库系统中的快速查找表。让我们以 Python 作为参考语言。

解决方案要求:

  1. 尽快检索孩子的 hasmaps!
  2. 哈希的parent估计总重量最多为 500 MB

用例如下:

  1. 客户端 Python 程序在数据存储中查询特定的子哈希
  2. 数据存储返回子哈希
  3. Python 程序将整个散列传递给特定函数,从散列中提取特定值(它已经知道要使用哪个键)并将其传递给第二个函数

您会推荐内存中的键值数据存储(例如 Redis)还是更经典的“关系”数据库解决方案?您建议我使用哪种数据模型?

4

3 回答 3

3

绝对与Redis一起使用。它不仅速度非常快,而且可以准确处理您需要的结构:http ://redis.io/commands#hash

在您的情况下,您可以避免读取整个“子哈希”,因为客户端“从哈希中提取特定值(它已经知道要使用哪个键)”

redis> HMSET myhash field1 "Hello" field2 "World"
OK
redis> HGET myhash field1
"Hello"
redis> HGET myhash field2
"World"

或者,如果您确实想要整个哈希:

redis> HGETALL myhash
1) "field1"
2) "Hello"
3) "field2"
4) "World"
redis>

当然,使用客户端库可以在一个可行的对象中提供结果,在你的例子中,一个 Python 字典。

于 2012-10-10T20:02:01.337 回答
2

使用redis-py 的示例代码,假设您已经安装了 Redis(最好是hiredis),将每个父级保存为哈希字段,将子级保存为序列化字符串,并在客户端处理序列化和反序列化:

JSON版本:

## JSON version
import json 
# you could use pickle instead, 
# just replace json.dumps/json.loads with pickle/unpickle

import redis

# set up the redis client
r = redis.StrictRedis(host = '', port = 6379, db = 0)

# sample parent dicts
parent0 = {'child0': {0:'a', 1:'b', 2:'c',}, 'child1':{5:'e', 6:'f', 7:'g'}}
parent1 = {'child0': {0:'h', 1:'i', 2:'j',}, 'child1':{5:'k', 6:'l', 7:'m'}}

# save the parents as hashfields, with the children as serialized strings
# bear in mind that JSON will convert the int keys to strings in the dumps() process
r.hmset('parent0', {key: json.dumps(parent0[key]) for key in parent0})
r.hmset('parent1', {key: json.dumps(parent0[key]) for key in parent1})


# Get a child dict from a parent
# say child1 of parent0
childstring = r.hget('parent0', 'child1') 
childdict = json.loads(childstring) 
# this could have been done in a single line... 

# if you want to convert the keys back to ints:
for key in childdict.keys():
    childdict[int(key)] = childdict[key]
    del childdict[key]

print childdict

泡菜版:

## pickle version
# For pickle, you need a file-like object. 
# StringIO is the native python one, whie cStringIO 
# is the c implementation of the same.
# cStringIO is faster
# see http://docs.python.org/library/stringio.html and
# http://www.doughellmann.com/PyMOTW/StringIO/ for more information
import pickle
# Find the best implementation available on this platform
try:
    from cStringIO import StringIO
except:
    from StringIO import StringIO

import redis

# set up the redis client
r = redis.StrictRedis(host = '', port = 6379, db = 0)

# sample parent dicts
parent0 = {'child0': {0:'a', 1:'b', 2:'c',}, 'child1':{5:'e', 6:'f', 7:'g'}}
parent1 = {'child0': {0:'h', 1:'i', 2:'j',}, 'child1':{5:'k', 6:'l', 7:'m'}}

# define a class with a reusable StringIO object
class Pickler(object):
    """Simple helper class to use pickle with a reusable string buffer object"""
    def __init__(self):
        self.tmpstr = StringIO()

    def __del__(self):
        # close the StringIO buffer and delete it
        self.tmpstr.close()
        del self.tmpstr

    def dump(self, obj):
        """Pickle an object and return the pickled string"""
        # empty current buffer
        self.tmpstr.seek(0,0)
        self.tmpstr.truncate(0)
        # pickle obj into the buffer
        pickle.dump(obj, self.tmpstr)
        # move the buffer pointer to the start
        self.tmpstr.seek(0,0)
        # return the pickled buffer as a string
        return self.tmpstr.read()

    def load(self, obj):
        """load a pickled object string and return the object"""
        # empty the current buffer
        self.tmpstr.seek(0,0)
        self.tmpstr.truncate(0)
        # load the pickled obj string into the buffer
        self.tmpstr.write(obj)
        # move the buffer pointer to start
        self.tmpstr.seek(0,0)
        # load the pickled buffer into an object
        return pickle.load(self.tmpstr)


pickler = Pickler()

# save the parents as hashfields, with the children as pickled strings, 
# pickled using our helper class
r.hmset('parent0', {key: pickler.dump(parent0[key]) for key in parent0})
r.hmset('parent1', {key: pickler.dump(parent1[key]) for key in parent1})


# Get a child dict from a parent
# say child1 of parent0
childstring = r.hget('parent0', 'child1') 
# this could be done in a single line... 
childdict = pickler.load(childstring) 

# we don't need to do any str to int conversion on the keys.

print childdict
于 2012-10-11T00:04:58.740 回答
0

在基于Javier提示进行快速搜索后,我想出了这个解决方案:我可以parent在 Redis 中实现单个哈希,其中值字段将是子哈希的字符串表示形式。通过这种方式,我可以快速阅读它们并从 Python 程序中评估它们。

举个例子,我的 Redis 数据结构类似于:

//write a hash with N key-value pairs: each value is an M key-value pairs hash
redis> HMSET parent_key1 child_hash "c1k1:c1v1, c1k2:c1v2, [...], c1kM:c1vM"
  OK
redis> HMSET parent_key2 child_hash "c2k1:c2v1, c2k2:c2v2, [...], c2kM:c2vM"
  OK
[...]
redis> HMSET parent_keyN child_hash "cNk1:cNv1, cNk2:cNv2, [...], cNkM:cNvM"
  OK

//read data
redis> HGET parent_key1 child_hash
  "c1k1:c1v1, c1k2:c1v2, [...], c1kM:c1vM"

然后我的 Python 代码只需要使用 Redis 绑定来查询所需的子哈希并返回它们的实际字符串表示;剩下要做的就是将字符串表示转换为相应的字典,因此可以方便地查找。

示例代码(如this answer中所建议):

>>> import ast
>>> # Redis query:
>>> #   1. Setup Redis bindings
>>> #   2. Ask for value at key: parent_key1
>>> #   3. Store the value to 's' string
>>> dictionary = ast.literal_eval('{' + s + '}')
>>> d
{c1k1:c1v1, c1k2:c1v2, [...], c1kM:c1vM}

希望我没有遗漏任何东西!

于 2012-10-10T21:30:53.790 回答