26

私はいくつかのデータ変更を行っていますが、メモリ内データベースに多数の辞書を貼り付けて、それに対して単純にクエリを実行できれば、かなり簡単になります。

たとえば、次のようなものです。

people = db([
    {"name": "Joe", "age": 16},
    {"name": "Jane", "favourite_color": "red"},
])
over_16 = db.filter(age__gt=16)
with_favorite_colors = db.filter(favorite_color__exists=True)

ただし、次の 3 つの交絡要因があります。

  • 一部の値は Python オブジェクトであり、それらをシリアル化することは問題外です (遅すぎて、ID が壊れます)。もちろん、これを回避することはできます (たとえば、すべてのアイテムを大きなリストに格納し、そのリスト内のインデックスをシリアル化することで... しかし、それにはかなりの手間がかかる可能性があります)。
  • 何千ものデータがあり、それらに対して検索を多用する操作 (グラフ トラバーサルなど) を実行するので、効率的な (つまり、インデックス付きの) クエリを実行できる必要があります。
  • 例のように、データは構造化されていないため、スキーマを事前に定義する必要があるシステムは扱いにくいでしょう。

では、そんなものは存在するのでしょうか。それとも、一緒に何かをクラッジする必要がありますか?

4

9 に答える 9

10

接続に特別な値を使用して、 sqlite3 標準ライブラリ モジュールを介してインメモリ SQLite データベースを使用するの:memory:はどうですか? on SQL ステートメントを記述したくない場合は、SQLAlchemyなどの ORM をいつでも使用して、インメモリ SQLite データベースにアクセスできます。

編集:値はPythonオブジェクトである可能性があり、シリアル化を回避する必要があると述べていることに気付きました。任意の Python オブジェクトをデータベースに格納する必要がある場合も、シリアル化が必要になります。

この 2 つの要件を守らなければならない場合、実用的な解決策を提案できますか? Python 辞書を Python 辞書のコレクションのインデックスとして使用しないのはなぜですか? それぞれのインデックスを構築するための特異なニーズがあるようです。クエリを実行する値を特定し、生成してそれぞれにインデックスを付ける関数を記述します。辞書のリスト内の 1 つのキーの可能な値は、インデックスのキーになります。インデックスの値は辞書のリストになります。探している値をキーとして指定して、インデックスをクエリします。

import collections
import itertools

def make_indices(dicts):
    color_index = collections.defaultdict(list)
    age_index = collections.defaultdict(list)
    for d in dicts:
        if 'favorite_color' in d:
            color_index[d['favorite_color']].append(d)
        if 'age' in d:
            age_index[d['age']].append(d)
    return color_index, age_index


def make_data_dicts():
    ...


data_dicts = make_data_dicts()
color_index, age_index = make_indices(data_dicts)
# Query for those with a favorite color is simply values
with_color_dicts = list(
        itertools.chain.from_iterable(color_index.values()))
# Query for people over 16
over_16 = list(
        itertools.chain.from_iterable(
            v for k, v in age_index.items() if age > 16)
)
于 2011-03-01T22:31:50.600 に答える
5

インメモリ データベース ソリューションがあまりにも多くの作業を必要とする場合は、次の方法で自分でフィルター処理を行うと便利です。

このget_filter関数は引数を取り、辞書をフィルター処理する方法を定義し、組み込みfilter関数に渡して辞書のリストをフィルター処理できる関数を返します。

import operator

def get_filter(key, op=None, comp=None, inverse=False):
    # This will invert the boolean returned by the function 'op' if 'inverse == True'
    result = lambda x: not x if inverse else x
    if op is None:
        # Without any function, just see if the key is in the dictionary
        return lambda d: result(key in d)

    if comp is None:
        # If 'comp' is None, assume the function takes one argument
        return lambda d: result(op(d[key])) if key in d else False

    # Use 'comp' as the second argument to the function provided
    return lambda d: result(op(d[key], comp)) if key in d else False

people = [{'age': 16, 'name': 'Joe'}, {'name': 'Jane', 'favourite_color': 'red'}]

print filter(get_filter("age", operator.gt, 15), people)
# [{'age': 16, 'name': 'Joe'}]
print filter(get_filter("name", operator.eq, "Jane"), people)
# [{'name': 'Jane', 'favourite_color': 'red'}]
print filter(get_filter("favourite_color", inverse=True), people)
# [{'age': 16, 'name': 'Joe'}]

これは、たとえば値が正規表現と一致するかどうかに基づいてフィルタリングするなど、より複雑なフィルタリングに非常に簡単に拡張できます。

p = re.compile("[aeiou]{2}") # matches two lowercase vowels in a row
print filter(get_filter("name", p.search), people)
# [{'age': 16, 'name': 'Joe'}]
于 2011-03-01T23:24:29.713 に答える
5

私が知っている唯一の解決策は、数年前にPyPIであるPyDbLiteで偶然見つけたパッケージです。大丈夫ですが、いくつか問題があります。

  1. まだすべてを pickle ファイルとしてディスクにシリアライズしたいと考えています。しかし、それは私が引き裂くのに十分簡単でした。(これも不要です。挿入されたオブジェクトがシリアライズ可能であれば、コレクション全体もシリアライズ可能です。)
  2. 基本的なレコード タイプはディクショナリで、独自のメタデータ、キーの下にある 2 つの int__id____version__.
  3. 索引付けは非常に単純で、レコード・ディクショナリの値のみに基づいています。レコード内のオブジェクトの属性に基づくなど、より複雑なものが必要な場合は、自分でコーディングする必要があります。(自分でやろうと思っていたのに、なかなか手をつけられなかったもの。)

作者もたまには頑張っているようです。複雑なクエリの優れた構文など、私が使用したときからいくつかの新機能があります。

あなたがピクルスを取り除いたと仮定すると(そして私が何をしたかをあなたに伝えることができます)、あなたの例は(テストされていないコード)になります:

from PyDbLite import Base

db = Base()
db.create("name", "age", "favourite_color")

# You can insert records as either named parameters
# or in the order of the fields
db.insert(name="Joe", age=16, favourite_color=None)
db.insert("Jane", None, "red")

# These should return an object you can iterate over
# to get the matching records.  These are unindexed queries.
#
# The first might throw because of the None in the second record
over_16 = db("age") > 16
with_favourite_colors = db("favourite_color") != None

# Or you can make an index for faster queries
db.create_index("favourite_color")
with_favourite_color_red = db._favourite_color["red"]

うまくいけば、それはあなたが始めるのに十分であることを願っています.

于 2011-03-01T23:53:49.917 に答える
3

オブジェクトのアイデンティティを追跡するために、ハッシュ可能なものを「アイデンティティ」する限り、比較できるはずです。

Zope Object Database(ZODB): http ://www.zodb.org/

PyTablesはうまく機能します: http ://www.pytables.org/moin

また、Python用のMetakitはうまく機能します:http: //equi4.com/metakit/python.html
supports columns, and sub-columns but not unstructured data

「ストリーム処理」を調べてください。データセットが非常に大きい場合は、これが役立つ場合があります:http: //www.trinhhaianh.com/stream.py/

シリアル化(ディスクへの書き込み)が可能なインメモリデータベースには、IDの問題が発生します。可能であれば、保存するデータをオブジェクトではなくネイティブタイプ(list、dict)として表すことをお勧めします。

NumPyは、メモリ内のデータ構造に対して複雑な操作を実行するように設計されており、独自のデータ構造を作成する場合は、ソリューションの一部になる可能性があることに注意してください。

于 2011-03-02T00:47:24.587 に答える
3

(2) と (3) を解決するJsonstoreという簡単なモジュールを書きました。あなたの例は次のようになります。

from jsonstore import EntryManager
from jsonstore.operators import GreaterThan, Exists

db = EntryManager(':memory:')
db.create(name='Joe', age=16)
db.create({'name': 'Jane', 'favourite_color': 'red'})  # alternative syntax

db.search({'age': GreaterThan(16)})
db.search(favourite_color=Exists())  # again, 2 different syntaxes
于 2012-11-13T06:37:26.060 に答える
1

すべての要件に準拠しているかどうかはわかりませんが、TinyDB (メモリ内ストレージを使用) もおそらく試してみる価値があります。

>>> from tinydb import TinyDB, Query
>>> from tinydb.storages import MemoryStorage
>>> db = TinyDB(storage=MemoryStorage)
>>> db.insert({'name': 'John', 'age': 22})
>>> User = Query()
>>> db.search(User.name == 'John')
[{'name': 'John', 'age': 22}]

そのシンプルさと強力なクエリ エンジンにより、一部のユース ケースでは非常に興味深いツールになります。詳細については、 http://tinydb.readthedocs.io/を参照してください。

于 2017-02-20T19:15:11.110 に答える
0

昨日開発を開始しましたが、まだ公開されていません。オブジェクトにインデックスを付け、高速なクエリを実行できるようにします。すべてのデータは RAM に保持され、スマートなロードと保存方法について考えています。テスト目的で、cPickle を介してロードおよび保存しています。

まだ興味がある場合はお知らせください。

于 2013-12-06T14:42:31.980 に答える
0

シリアル化を回避したい場合は、MongoDB が役に立ちます。PyMongo は、説明したものとほぼ同じインターフェースを提供します。シリアル化することにした場合、Mongodb はメモリ マップされているため、ヒットはそれほど悪くはありません。

于 2011-03-01T22:32:14.667 に答える
0

isinstance()、hasattr()、getattr()、setattr() だけでやりたいことができるはずです。

ただし、完了する前に、かなり複雑になります。

すべてのオブジェクトを大きなリストに格納し、各オブジェクトに対してクエリを実行して、それが何であるかを判断し、特定の属性または値を探してから、値とオブジェクトをタプルのリストとして返すことができると思います。その後、戻り値を簡単に並べ替えることができます。copy.deepcopy は、あなたの親友であり、最悪の敵です。

楽しいように聞こえる!幸運を!

于 2011-03-01T22:59:19.390 に答える