Pregunta

decir que tengo una sencilla tabla que contiene nombre de usuario, nombre, apellido.

¿Cómo expreso esto en Berkeley DB?

Actualmente estoy usando bsddb como la interfaz.

Saludos.

¿Fue útil?

Solución

Usted tiene que elegir una "columna" como la clave (debe ser único; me imagino que sería "nombre de usuario" en su caso) - las únicas vías búsquedas serán siempre posiblemente sucederá. Las otras columnas se pueden hacer para ser el valor de cadena única de esa clave por la forma que desee, desde el decapado de sencilla de unirse con un personaje que está garantizado que nunca ocurren en cualquiera de las columnas, como `\ 0' para muchos tipos de "cadenas de texto legibles".

Si tiene que ser capaz de buscar por diferentes teclas que necesitará otros, complementarios e independientes bases de datos bsddb establecidas como "índices" en su mesa principal - es un montón de trabajo, y hay una gran cantidad de literatura sobre el tema . (Alternativamente, se mueve a una tecnología de mayor abstracción, como SQLite, que se ocupa de la indexación perfectamente en su nombre; -)

.

Otros consejos

tl, dr: Para expresar varias columnas en una tienda ordenó valor clave como db Berkley que necesita para aprender acerca de composición tecla . Mira mis otras respuestas sobre bsddb para obtener más información.

Hay varias maneras de hacer que el uso de clave ordenó / tienda de valor.

La solución más simple es como valores JSON con una correcta clave.

Ahora es probable que desee de creación de índices sobre esas columnas para recuperar documentos sin tener que iterar sobre todo el mapa hash para encontrar el objeto correcto. Para que pueda utilizar un secondaryDB que va a construir de forma automática el índice de tú. O se puede realizar un índice usted mismo.

Si no quiere tratar con embalaje (y es una buena idea para poner en marcha), se pueden aprovechar DB.set_bt_compare que permitirá utilizar cPickle , JSON o msgpack para ambas claves y valores sin dejar de tener un orden que tiene sens para crear índices y consultas que hacen. Este es el método más lento pero introducir el patrón de composición tecla .

Para aprovechar al máximo lo que recetó clave es, se puede hacer uso de Cursor.set_range(key) para ajustar la posición de la db en el comienzo de una consulta.

Otro patrón, se denomina patrón de EAV Tiendas de tuplas que siguen el esquema de (entity, attribute, value) y luego construir varias índice mediante la permutación de esa tupla. Aprendí este patrón estudiando datomic.

Por menos ressource base de datos de hambre, que irá el "estático escrito" camino y almacenar la mayor cantidad posible de información común en los documentos de mesa y divididas "metadatos" (que en realidad son RDBMS tablas) en su propio mapa hash.

Para empezar aquí es una base de datos de ejemplo utilizando bsddb (pero se podría construir utilizando otro almacén de clave / valor ordenado como wiredtiger o LevelDB) que implementa el patrón de EAV. En esta implementación EAV de intercambio I de IKV que se traduce en Identificador único, clave, valor. El resultado de eficacia general es que usted tiene una base de datos de esquema menos documento totalmente indexada. Creo que es un buen compromiso entre la eficiencia y facilidad de 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))
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top