1

キーに関連付けられたリストをキー値データベースに格納する最良の方法を検索します (berkleydbまたはのようにleveldb)

例: ユーザーとユーザーからユーザーへの注文があります。各ユーザーの注文 ID のリストを保存して、範囲選択 (ページネーション用) ですばやくアクセスできるようにしたいと考えています。

この構造をどのように保存しますか?

ユーザーごとにシリアル化可能な形式で保存したくありません。

user_1_orders = serialize(1,2,3..)
user_2_orders = serialize(1,2,3..)

リストが長くなる可能性があるため

店舗注文 ID をキーとしてユーザーごとに個別の db ファイルを考えていますが、これでは範囲選択の問題は解決しません。範囲でユーザー ID を取得したい場合はどうすればよいです[5000:5050]か?

については知っていますが、またはredisのようなキー値の実装に興味があります。berkleydbleveldb

4

4 に答える 4

2

単一のリストから始めましょう。単一のハッシュマップで作業できます。

  1. 0ユーザーの注文数を行に保存する
  2. 新しい注文ごとに、カウントがインクリメントされた新しい行を保存します

したがって、夜ハッシュマップは次のようになります。

key | value
-------------
 0  |   5
 1  | tomato
 2  | celery
 3  | apple
 4  | pie
 5  | meat

キーの着実なインクリメントにより、すべてのキーが一意であることを確認します。データベースがキー順であり、 pack 関数が整数を正しく順序付けられたバイト配列のセットに変換するという事実を考えると、リストのスライスを取得できます。5000 から 5050 の間の注文を取得するには、bsddbCursor.set_rangeまたは leveldb createReadStream(js api)を使用できます。

次に、複数のユーザー注文に拡張しましょう。複数のハッシュマップを開くことができる場合は、複数のハッシュマップを使用して上記を使用できます。たぶん、いくつかのシステムの問題 (開いている fds の最大 nb またはディレクトリごとのファイルの最大数) に遭遇するでしょう。したがって、単一のハッシュマップを使用して、複数のユーザーで同じハッシュマップを共有できます。

pack以下で説明することは、辞書式順序 (バイトオーダー) を使用して正しくキーを設定すると、leveldb と bsddb の両方で機能します。だから私はあなたが機能を持っていると仮定しますpack。bsddb では、pack自分で関数を作成する必要があります。インスピレーションを得るには、wiredtiger.packingまたはbytekeyをご覧ください。

原則は、ユーザーの ID を使用してキーの名前空間を作成することです。キーコンポジションとも呼ばれます。

データベースが次のようになっているとします。

   key   |  value
-------------------
  1  | 0 |    2       <--- count column for user 1
  1  | 1 |  tomato
  1  | 2 |  orange 
    ...      ...
  32 | 0 |    1       <--- count column for user 32
  32 | 1 |  banna
    ...  |   ...

このデータベースは、次の (疑似) コードで作成します。

db.put(pack(1, make_uid(1)), 'tomato')
db.put(pack(1, make_uid(1)), 'orange')
...
db.put(pack(32, make_uid(32)), 'bannana')

make_uid実装は次のようになります。

def make_uid(user_uid):
    # retrieve the current count
    counter_key = pack(user_uid, 0)
    value = db.get(counter_key)
    value += 1  # increment
    # save new count
    db.put(counter_key, value)
    return value

次に、正しい範囲検索を行う必要があります。これは、単一の複合キーに似ています。bsddb apiを使用して、 userとのcursor.set_range(key)間のすべてのアイテムを取得します。5000505042

def user_orders_slice(user_id, start, end):
    key, value = cursor.set_range(pack(user_id, start))
    while True:
        user_id, order_id = unpack(key)
        if order_id > end:
            break
        else:
            # the value is probably packed somehow...
            yield value
            key, value = cursor.next()

エラーチェックは行われません。とりわけuser_orders_slice(42, 5000, 5050)、リストから項目を削除した場合、スライスによって 51 個の項目が引き裂かれることは保証されません。たとえばアイテムをクエリする正しい方法50は、user_orders_query(user_id, start, limit)` を実装することです。

理解していただければ幸いです。

于 2015-08-21T22:20:27.403 に答える
0

BerkeleyDB では、キーごとに複数の値を、並べ替えられた順序または並べ替えられていない順序で格納できます。これが最も自然な解決策でしょう。LevelDB にはそのような機能はありません。LMDB( http://symas.com/mdb/ )を調べる必要がありますが、ソートされた複数値キーもサポートしており、他のいずれよりも小さく、高速で、信頼性が高くなります。

于 2013-12-09T14:02:09.053 に答える