Domanda

Di 'Ho una semplice tabella che contiene il nome utente, nome, cognome.

Come faccio a esprimere questo concetto in Berkeley DB?

Attualmente sto usando bsddb come interfaccia.

Saluti.

È stato utile?

Soluzione

Si deve scegliere una "colonna" come chiave (deve essere unico, immagino che sarebbe "username" nel tuo caso) - l'unico modo in cui le ricerche potrà mai accadere. Le altre colonne possono essere fatti per essere il valore stringa singola di quella chiave da qualsiasi modo che ti piace, dal decapaggio alla semplice entrare con un carattere che è garantito per non verificarsi in una delle colonne, come ad esempio `\ 0' per molti tipi di "stringhe di testo leggibili".

Se avete bisogno di essere in grado di cercare per diverse chiavi avrete bisogno di altri, complementari e distinte banche dati Bsddb impostati come "indici" nel tuo tabella principale - E 'un sacco di lavoro, e c'è un sacco di letteratura sull'argomento . (In alternativa, si passa a una tecnologia superiore di astrazione, come ad esempio SQLite, che gestisce l'indicizzazione ordinatamente a vostro nome; -)

.

Altri suggerimenti

tl, dr: Per esprimere più colonne in un ordinato chiavi valore come db Berkley è necessario conoscere composizione tasto . Guardate le mie altre risposte su bsddb per saperne di più.

Ci sono diversi modi per farlo con il tasto ordinato / negozio di valore.

La soluzione più semplice è quella di come valori JSON con una chiave corretta .

Ora probabilmente si desidera indice di costruire su quelle colonne di recuperare i documenti senza dover iterare su tutta la HashMap per trovare l'oggetto giusto. Per questo è possibile utilizzare un secondaryDB che costruirà automaticamente l'indice per voi. Oppure si può costruire l'indice di te stesso.

Se non si vuole affrontare con imballaggio (ed è una buona idea per l'avvio), è possono usufruire di DB.set_bt_compare che vi permetterà di utilizzare cPickle , jSON o msgpack per entrambi i tasti e valori, pur avendo un ordine che rende sens di creare indici e query facendo. Questo è il metodo più lento ma introdurre il modello di composizione tasto .

Per sfruttare appieno ciò che ha ordinato chiave è, si può fare uso di Cursor.set_range(key) per impostare la posizione del db, all'inizio di una query.

Un altro modello, è chiamato il EAV modello memorizza le tuple che seguono il (entity, attribute, value) schema e poi si costruiscono vari indice utilizzando permutazione di quel tupla. Ho imparato questo modello studiando datomic.

Per meno ressource database di fame, si andrà alla "statico digitato" via e conservare il più possibile di informazioni comuni nei documenti di tabella e split "metadati" (che sono in realtà RDBMS tabelle) nella propria hashmap.

Per iniziare qui è un database di esempio utilizzando bsddb (ma si potrebbe costruire utilizzando un altro negozio chiave / valore ordinato come wiredtiger o LevelDB) che implementa il pattern EAV. In questa implementazione io di swap EAV per IKV che si traduce in identificatore univoco, Chiave, Valore. Il risultato overal è che si dispone di un database di schema meno documento completamente indicizzato. Penso che sia un buon compromesso tra efficienza e la facilità d'uso.

import struct

from json import dumps
from json import loads

from bsddb3.db import DB
from bsddb3.db import DBEnv
from bsddb3.db import DB_BTREE
from bsddb3.db import DB_CREATE
from bsddb3.db import DB_INIT_MPOOL
from bsddb3.db import DB_LOG_AUTO_REMOVE


def pack(*values):
    def __pack(value):
        if type(value) is int:
            return '1' + struct.pack('>q', value)
        elif type(value) is str:
            return '2' + struct.pack('>q', len(value)) + value
        else:
            data = dumps(value, encoding='utf-8')
            return '3' + struct.pack('>q', len(data)) + data
    return ''.join(map(__pack, values))


def unpack(packed):
    kind = packed[0]
    if kind == '1':
        value = struct.unpack('>q', packed[1:9])[0]
        packed = packed[9:]
    elif kind == '2':
        size = struct.unpack('>q', packed[1:9])[0]
        value = packed[9:9+size]
        packed = packed[size+9:]
    else:
        size = struct.unpack('>q', packed[1:9])[0]
        value = loads(packed[9:9+size])
        packed = packed[size+9:]
    if packed:
        values = unpack(packed)
        values.insert(0, value)
    else:
        values = [value]
    return values


class TupleSpace(object):
    """Generic database"""

    def __init__(self, path):
        self.env = DBEnv()
        self.env.set_cache_max(10, 0)
        self.env.set_cachesize(5, 0)
        flags = (
            DB_CREATE |
            DB_INIT_MPOOL
        )
        self.env.log_set_config(DB_LOG_AUTO_REMOVE, True)
        self.env.set_lg_max(1024 ** 3)
        self.env.open(
            path,
            flags,
            0
        )

        # create vertices and edges k/v stores
        def new_store(name):
            flags = DB_CREATE
            elements = DB(self.env)
            elements.open(
                name,
                None,
                DB_BTREE,
                flags,
                0,
            )
            return elements
        self.tuples = new_store('tuples')
        self.index = new_store('index')
        self.txn = None

    def get(self, uid):
        cursor = self.tuples.cursor()

        def __get():
            record = cursor.set_range(pack(uid, ''))
            if not record:
                return
            key, value = record
            while True:
                other, key = unpack(key)
                if other == uid:
                    value = unpack(value)[0]
                    yield key, value
                    record = cursor.next()
                    if record:
                        key, value = record
                        continue
                    else:
                        break
                else:
                    break

        tuples = dict(__get())
        cursor.close()
        return tuples

    def add(self, uid, **properties):
        for key, value in properties.items():
            self.tuples.put(pack(uid, key), pack(value))
            self.index.put(pack(key, value, uid), '')

    def delete(self, uid):
        # delete item from main table and index
        cursor = self.tuples.cursor()
        index = self.index.cursor()
        record = cursor.set_range(pack(uid, ''))
        if record:
            key, value = record
        else:
            cursor.close()
            raise Exception('not found')
        while True:
            other, key = unpack(key)
            if other == uid:
                # remove tuple from main index
                cursor.delete()

                # remove it from index
                value = unpack(value)[0]
                index.set(pack(key, value, uid))
                index.delete()

                # continue
                record = cursor.next()
                if record:
                    key, value = record
                    continue
                else:
                    break
            else:
                break
        cursor.close()

    def update(self, uid, **properties):
        self.delete(uid)
        self.add(uid, **properties)

    def close(self):
        self.index.close()
        self.tuples.close()
        self.env.close()

    def debug(self):
        for key, value in self.tuples.items():
            uid, key = unpack(key)
            value = unpack(value)[0]
            print(uid, key, value)

    def query(self, key, value=''):
        """return `(key, value, uid)` tuples that where
        `key` and `value` are expressed in the arguments"""
        cursor = self.index.cursor()
        match = (key, value) if value else (key,)

        record = cursor.set_range(pack(key, value))
        if not record:
            cursor.close()
            return

        while True:
            key, _ = record
            other = unpack(key)
            ok = reduce(
                lambda previous, x: (cmp(*x) == 0) and previous,
                zip(match, other),
                True
            )
            if ok:
                yield other
                record = cursor.next()
                if not record:
                    break
            else:
                break
        cursor.close()


db = TupleSpace('tmp')
# you can use a tuple to store a counter
db.add(0, counter=0)

# And then have a procedure doing the required work
# to alaways have a fresh uid
def make_uid():
    counter = db.get(0)
    counter['counter'] += 1
    return counter['counter']

amirouche = make_uid()
db.add(amirouche, username="amirouche", age=30)
print(db.get(amirouche))
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top