我正在做一些数据调整,如果我可以在内存数据库中粘贴一堆字典,然后对它进行简单的查询,这将更加简单。
例如:
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)
但有三个混淆因素:
那么,这样的事情存在吗?或者我需要一起解决问题吗?
答案 0 :(得分:10)
如何通过sqlite3 standard library module使用内存中的SQLite数据库,使用特殊值:memory:
进行连接?如果您不想编写on SQL语句,则可以始终使用ORM(如SQLAlchemy)来访问内存中的SQLite数据库。
编辑:我注意到您声明值可能是Python对象,还需要避免序列化。要求将任意Python对象存储在数据库中也需要序列化。
如果您必须遵守这两项要求,我可以提出切实可行的解决方案吗?为什么不直接使用Python词典作为Python词典集合的索引?听起来你需要建立每个指数的特殊需求;找出你要查询的值,然后编写一个函数来为每个值生成和索引。您的dicts列表中一个键的可能值将是索引的键;索引的值将是字典列表。通过给出您要查找的值作为键来查询索引。
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)
)
答案 1 :(得分: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'}]
答案 2 :(得分:5)
我所知道的唯一解决方案是我几年前在PyPI PyDbLite上偶然发现的一个软件包。没关系,但问题很少:
__id__
和__version__
下有两个整数。作者似乎偶尔也在努力。我使用它时有一些新功能,包括一些很好的复杂查询语法。
假设你剔除了酸洗(我可以告诉你我做了什么),你的例子就是(未经测试的代码):
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"]
希望这足以让你开始。
答案 3 :(得分:3)
至于“身份”任何可以清洗的东西,你应该能够比较,以跟踪对象的身份。
Zope对象数据库(ZODB): http://www.zodb.org/
PyTables效果很好: http://www.pytables.org/moin
同样Metakit for Python效果很好:
http://equi4.com/metakit/python.html
supports columns, and sub-columns but not unstructured data
研究“流处理”,如果您的数据集非常大,这可能很有用: http://www.trinhhaianh.com/stream.py/
任何可以序列化(写入磁盘)的内存数据库都会出现您的身份问题。如果可能的话,我建议将要存储的数据表示为本机类型(list,dict)而不是对象。
请记住,NumPy旨在对内存中的数据结构执行复杂的操作,如果你决定推出自己的解决方案,它可能是你的解决方案的一部分。
答案 4 :(得分:3)
我写了一个名为Jsonstore的简单模块,它解决了(2)和(3)。以下是您的示例:
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
答案 5 :(得分:0)
如果您愿意解决序列化问题,MongoDB可以为您服务。 PyMongo提供的界面几乎与您描述的界面完全相同。如果您决定序列化,那么由于Mongodb是内存映射的,所以命中不会那么糟糕。
答案 6 :(得分:0)
应该可以使用isinstance(),hasattr(),getattr()和setattr()完成您想要做的事情。
然而,在你完成之前,事情会变得相当复杂!
我想可以将所有对象存储在一个大列表中,然后对每个对象运行查询,确定它是什么并查找给定的属性或值,然后将值和对象作为元组列表返回。然后你可以很容易地对你的返回值进行排序。 copy.deepcopy将是你最好的朋友,也是你最大的敌人。
听起来很有趣!祝你好运!
答案 7 :(得分:0)
我昨天开始开发一个,但尚未发布。它为您的对象编制索引,并允许您运行快速查询。所有数据都保存在RAM中,我正在考虑智能加载和保存方法。出于测试目的,它通过cPickle加载和保存。
如果您仍然感兴趣,请告诉我。
答案 8 :(得分:0)
不确定它是否符合您的所有要求,但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/。