Question

Dire que j'ai une table simple qui contient le nom d'utilisateur, nom, prénom.

Comment puis-je exprimer en Db berkeley?

Je suis actuellement en utilisant bsddb comme l'interface.

Vive.

Était-ce utile?

La solution

Vous devez choisir une « colonne » comme la clé (doit être unique, j'imagine que ce serait « nom d'utilisateur » dans votre cas) - les seules recherches de façon ne se fera jamais peut-être. Les autres colonnes peuvent être faites pour être la valeur de chaîne unique de cette clé par quelque façon que vous le souhaitez, de décapage à simple, se joindre à un caractère qui est garanti de se produire jamais dans l'une des colonnes, comme `\ 0' pour de nombreux types de "chaînes de texte lisibles".

Si vous devez être en mesure de rechercher par des clés différentes, vous aurez besoin d'autres, les bases de données bsddb supplémentaires et distincts mis en place comme « indices » dans votre table principale - il y a beaucoup de travail, et il y a beaucoup de littérature sur le sujet . (Sinon, vous passez à une technologie plus-abstraction, comme sqlite, qui gère l'indexation d'une manière ordonnée en votre nom; -).

Autres conseils

tl, dr: Pour exprimer plusieurs colonnes dans un magasin de valeur clé ordonnée comme Berkley db vous devez en apprendre davantage sur composition clé . Regardez mes autres réponses sur bsddb pour en savoir plus.

Il y a plusieurs façons de le faire en utilisant la clé ordonnée / magasin de valeur.

La solution la plus simple est de stocker des documents en tant que valeurs JSON avec une clé correcte.

Maintenant, vous voulez probablement construire l'index sur ces colonnes pour récupérer des documents sans avoir à itérer sur tous les hashmap pour trouver l'objet correct. Pour cela, vous pouvez utiliser un secondaryDB qui construira automatiquement l'index toi. Ou vous pouvez construire vous-même l'indice.

Si vous ne voulez pas traiter avec l'emballage clé (et il est une bonne idée pour le démarrage), vous peut profiter de DB.set_bt_compare qui vous permettra d'utiliser cPickle , JSON ou msgpack pour les clés et les valeurs tout en ayant un ordre qui fait sens pour créer des indices et des requêtes faites. Ceci est la méthode plus lente, mais introduire le modèle de composition clé .

Pour profiter pleinement ce qui est commandé clé, vous pouvez utiliser Cursor.set_range(key) pour régler la position de la DB au début d'une requête.

Un autre modèle, est appelée modèle EAV magasins tuples qui suivent le schéma (entity, attribute, value) puis vous construisez différents index en utilisant la permutation de ce tuple. J'ai appris ce modèle studing datomic.

Pour moins base de données faim de ressource, vous allez le chemin « typé statique » et stocker autant que possible des informations communes dans le tableau « métadonnées » et des documents séparés (qui sont SGBDR vraiment tables) dans leur propre hashmap.

Pour démarrer ici est une base de données exemple en utilisant bsddb (mais vous pouvez le construire en utilisant un autre magasin de clés commandé / valeur comme wiredtiger ou LevelDB) qui met en œuvre le modèle EAV. Dans cette implémentation j'échange EAV pour IKV qui se traduit par identifiant unique, clé, valeur. Le résultat overal est que vous avez un schéma entièrement indexé moins base de données de documents. Je pense qu'il est un bon compromis entre l'efficacité et la facilité d'utilisation.

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))
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top