跳转到主要内容

一个由Redis支持的超级快速ORM,支持O(1)搜索的模型和索引,并支持存储原生/复杂类型和对象

项目描述

这是一个支持索引的Redis支持的非常非常快的ORM风格框架。它具有O(1)效率的搜索功能!

您可以将原生Python类型(列表、对象、字符串、整数等)存储和检索。

IndexedRedis支持比较中的“等于”和“不等于”运算符。它还提供对替换整个数据集(基于模型)的完整原子支持,这对于提供快速的SQL前端非常有用。在这种情况下,一个按间隔运行的任务将从一个SQL后端检索/计算数据集,并对前端查询的数据集执行原子替换。

自6.0.0版本起,IndexedRedis还提供了对外部引用(如SQL中的外键一对一、一对多或多对多关系)的支持,这允许您直接将SQL模型转换为Redis模型,从而大大提高性能。

在数据检索后,还提供进一步客户端过滤(如大于、包含等)(请参阅以下“过滤结果”)

我的测试表明,在使用flask/mysql和IndexedRedis之间的等效模型时,性能可以提高600% - 1200%,但如果你直接以IndexedRedis模型设计存储,你将能够实现更高的提升。

它与python 2.7和python 3兼容。它已在python 2.7、3.4、3.5、3.6上进行了测试。

5.0 状态

版本5.0.0将与之前版本略有不兼容,因为它移除了一些旧遗留功能,改进了许多现有功能,并更改了一些行为。

你可以通过转换指南了解转换所需步骤,该指南可在以下位置找到:https://github.com/kata198/indexedredis/blob/5.0branch/CONVERTING_TO_5.0.0

变更的详细信息,以及转换指南中省略的增强和错误修复,可以在5.0.0版本日志中找到:https://github.com/kata198/indexedredis/blob/5.0branch/Changelog

自动和原生类型

从4.0版本开始,IndexedRedis支持定义字段,这些字段将自动转换为/从原生Python类型(如int、float、datetime)转换,以及可以表示为json(字典、列表)或支持pickle的对象。你只需提供其原生格式中的类型,所有的转换都在幕后完成。当获取对象时,返回的对象也包含其原生类型的字段。

IndexedRedis还支持更多高级功能,例如自动pickle/unpickle字段、压缩/解压缩、base64编码/解码,甚至可以通过标准接口定义自己的自定义字段类型。

有关更多信息,请参阅下文的“高级字段”部分。

API参考

并非所有方法和类型都包含在此文档中。

有关完整的pydoc参考,请参阅

https://pythonhosted.org/indexedredis/

http://htmlpreview.github.io/?https://github.com/kata198/IndexedRedis/blob/master/doc/IndexedRedis.html?_cache_vers=1

以下是一个快速概述/概览

IndexedRedisModel

你应该扩展此类型来定义你的模型。

示例模型

class Song(IndexedRedisModel)

FIELDS = [ \

IRField(‘artist’),

IRField(‘title’),

IRField(‘album’),

IRField(‘track_number’,valueType=int), # 自动转换为/从int

IRField(‘duration’,defaultValue=’0:00’),

IRField(‘releaseDate’,valueType=datetime.datetime), # 自动转换为/从datetime

IRField(‘description’),

IRField(‘copyright’),

IRRawField(‘mp3_data’), # 不要尝试编码/解码数据

IRCompressedField(‘thumbnail’,compressMode=’gzip’), # 使用“gzip”压缩在存储中压缩此字段

IRField(‘tags’,valueType=list),

# “lyrics”将在对象上是一个utf-8 unicode值,并将其压缩/解压缩到/从存储中 IRFieldChain(‘lyrics’,[ IRUnicodeField(encoding=’utf-8’), IRCompressedField() ]),defaultValue=’No lyrics found’ ),

]

INDEXED_FIELDS = [ \

‘artist’,

‘title’,

‘track_number’,

]

KEY_NAME = ‘Songs’

模型属性

FIELDS - 必需。一个字符串或IRField对象(或其子类)的列表,这些对象命名了可用于存储的字段。(见下文“高级字段”部分)

示例:[IRField(‘name’), IRField(‘description’), IRField(‘model’), IRFixedPointField(‘Price’,2), IRField(‘timestamp’,valueType=datetime), IRField(‘remainingStock’,valueType=int)]

INDEXED_FIELDS - 包含将进行索引的字段名称的字符串列表。只能过滤索引字段。添加插入/删除时间。此处列出的名称必须与FIELDS中给出的字段名称匹配。

示例:[‘Name’,‘model’]

KEY_NAME - 必需。表示此模型的唯一名称。将其视为表名。

示例:‘StoreItems’

REDIS_CONNECTION_PARAMS - 可选 - 提供传递给“redis.Redis”以构造redis对象的参数。在这里,您可以定义每个模型的默认连接参数的覆盖。

从5.0.0版本开始,仅为此模型定义此字段以使用默认连接之外的连接。您不再需要在每个模型上设置此选项。

有关更多信息,请参阅下面的“连接到Redis”部分。

如果未定义或为空,将使用默认参数。如果存在任何字段,它们将覆盖继承的默认连接参数。

示例:{'host' : '192.168.1.1'}

高级字段

从版本4.0开始,IndexedRedis允许您在FIELDS元素中传递类型为IRField(扩展str)的元素。

从5.0.0版本开始,所有字段必须以某种方式扩展IRField。那些不扩展的将生成弃用警告,并且字段将被转换为IRClassicField(与IRField相同,但默认为空字符串而不是irNull)。

这样做可以指定有关字段的某些属性。

示例

FIELDS = [ IRField('name'), IRField('age', valueType=int), IRField('birthday', valueType=datetime.datetime) ]

字段名称

第一个参数是字段名称的字符串。

类型

您可以通过传递“valueType”将值自动转换为特定类型(IRField或使用几种扩展字段之一)

(例如,IRField('age', valueType=int))

如果使用“bool”,则值0和大小写不敏感的字符串“false”将结果为False,而1或“true”将结果为True。

当使用浮点数时,请考虑使用IRFixedPointField,它支持索引,并且与平台无关的相同表示形式(与“float”不同)。

浮点数以跨平台工作。使用定点数字作为字符串类型(例如,myFixedPoint = '%2.5f' % (10.12345))

IRField支持“valueType”,大多数其他字段类型处理特定类型,因此没有此类参数。

空值

空值由一个静态单例表示,称为“irNull”(类型为IRNullType)。

对于除IRClassicField之外的所有类型(IRClassicField默认为空字符串),字段的默认值(当未设置时)为irNull。可以通过将“defaultValue=somethingElse”传递给IRField构造函数来更改此值。

irNull不等于空字符串,或除了另一个irNull之外的所有内容。这是为了区分,例如,没有分配的int与int(0)

您可以使用在IndexedRedis或IndexedRedis.fields中找到的“irNull”变量来检查类型化的字段。

例如。

from IndexedRedis import irNull

# 可以直接在模型过滤中使用,notDangerFive = MyModel.objects.filter(dangerLevel__ne=irNull).filter(dangerLevel__ne=5).all()

# 或在可查询列表中,或直接比较(未显示)myResults = MyModel.objects.filter(something='value').all()

notDangerFive = myResults.filter(dangerLevel__ne=irNull).filter(dangerLevel__ne=5)

默认值

所有字段(除IRClassicField外)支持在构造IRField对象时提供的“defaultValue”参数。

对于所有字段(除IRClassicField外),此参数的默认值是“irNull”(见下文)。对于IRClassicField,默认值保持为空字符串,并且不能更改(以与5.0.0之前的普通字符串字段兼容)。

高级类型

以下是在FIELDS数组中使用可能的字段类型,可以像“from IndexedRedis.fields import NAME”一样导入

IRField - 标准字段,接受一个名称和一个“valueType”,这是一个本地Python类型,或任何实现__new__的单参数类型,返回对象。有关datetime和json的实现示例,请参阅IndexedRedis/fields/FieldValueTypes。

如果没有定义valueType,则类型为str/unicode(与4.0之前相同),并使用默认编码(请参阅set/getDefaultIREncoding函数)

除非类型是json类型或浮点数(使用IRFixedPointField在浮点数上建立索引)否则可索引。

IRBase64Field - 在Base64编码和解码之间转换。

可索引。

IRCompressedField - 在存储前自动压缩,在检索后自动解压缩。参数“compressMode”目前支持“zlib”(默认)、“bz2”或“lzma”。

可索引。

IRFixedPointField - 带有固定小数位数的浮点数。此类类型支持使用浮点数进行索引,而IRField(…valueType=float)不支持,因为不同平台有不同的精度、舍入等。通过参数decimalPlaces(默认为5)定义小数点后的精度。

可索引。

IRPickleField - 在存储前自动将给定的对象序列化,在检索后反序列化。

不可索引,因为Python 2和3之间的表示不同,以及系统相关的repr变化。

IRUnicodeField - 带有参数“encoding”的字段,用于定义此字段的编码。使用此字段来支持具有任意编码的字段,因为IRField将使用默认编码来处理字符串。

可索引

IRBytesField - 强制数据为“bytes”,Python 2和Python 3兼容。如果您需要Python 3专用,可以使用IRField(valueType=bytes)。对于完全不进行编码/解码,请参阅IRRawField。

可索引

IRClassicField - 模仿FIELDS 5.0.0之前的普通字符串条目行为的字段。此字段默认为空字符串,并且始终使用默认IREncoding进行编码/解码。

可索引

IRRawField - 不在Redis中转换的字段。在检索时,它始终是“bytes”类型(或Python 2中的str)。在Python 3中,它与IRField(…valueType=None)非常相似,但Python 2需要此字段来存储二进制数据而不会遇到编码问题。

不可索引 - 无解码

IRForeignLinkField - 提供对另一个模型的引用(在SQL中想到“外键”)。使用此功能来引用模型中的其他模型。该字段链接到单个外对象或irNull。

使用“foreignKey”参数接受链接的模型。

有关更多信息,请参阅“外部链接”部分。

可索引

IRForeignMultiLinkField - 提供对另一个模型的引用(在SQL中想到“外键”)。使用此功能来引用模型中的多个其他模型。该模型链接到一个或多个外对象,或irNull。

使用“foreignKey”参数接受链接的模型。

有关更多信息,请参阅“外部链接”部分。

可索引。注意,过滤器必须包含完整列表(pks、objs或它们的组合)。必须客户端执行“包含项目”式过滤器。

IRFieldChain - 将多个字段类型链接在一起。例如,使用此功能压缩值的Base64表示形式或压缩utf-16数据。有关更多详细信息,请参阅下面的部分。

如果所有链接的字段都是可索引的,则可索引。

链式连接多个类型

“链式连接”允许您对单个字段应用多个类型。例如,假设您有一些需要压缩以进行存储的utf-16数据。

示例

FIELDS = [

IRFieldChain(‘longData’,[IRUnicodeField(encoding='utf-16'), IRCompressedField()])

]

IRFieldChain类似于常规IRField,第一个参数是字段名称,它有一个可选的“defaultValue”参数。

不同之处在于第二个参数chainedFields接受一个其他字段类型的列表。

在存储时,将值通过列表中的每个类型从左到右传递。

在检索时,检索到的值将逆向通过这些链接字段,从右到左。

最左侧元素(第一个元素)的输出定义了访问对象时将找到的数据类型。

因此,在上面的示例中,“myObj.longData”将是一个utf-16字符串。在访问数据库时,该utf-16字符串将被解码然后压缩以进行存储。在检索时,它将被解压缩然后转换回utf-16。

您可以在IRFieldChain上指定一个defaultValue,通过将“defaultValue=X”作为构造函数的参数来实现。但是,如果在链中的任何字段上提供了“defaultValue”,则将被忽略。

哈希查找(性能)

如果您想要在非常大的字符串/字节(如基因组)上进行索引/搜索,IndexedRedis支持对键进行哈希处理,即值将作为本身存储,但用于查找的键引用将是该字符串的哈希。

这提高了性能,节省了网络流量,并减少了存储需求。

为此,将IRField的“hashIndex”属性设置为True。

FIELDS = [ \

IRField('genomeStr', hashIndex=True)

]

就这样!过滤和检索等所有操作保持不变(即您直接使用值,就像“hashIndex”为False一样),但在幕后,所有查找都将使用值的MD5哈希来完成。

将现有模型转换为/从哈希索引

IndexedRedis提供了辅助方法来自动将现有的未哈希键转换为哈希,并将哈希键转换回未哈希。

为此,相应地更改您的IndexedRedisModel,然后调用(对于名为MyModel的模型类)

MyModel.objects.compat_convertHashedIndexes()

这将删除任何支持“hashIndex”属性的IRField的哈希和非哈希键值。如果您仅调用“reindex”并且更改了任何字段的“hashIndex”属性,则将留下持久的关键值。

默认情况下(fetchAll=True),此函数将检索此特定模型的全部记录,并对它们逐个操作。这更有效,但如果内存限制是问题,则可以传递fetchAll=False,这将检索一个对象,转换索引,保存,然后检索下一个对象。这较慢,但使用的内存较少。

在此函数调用期间,不应使用任何模型(在更改模式时使用它本来就没有意义)。

连接到Redis

您的Redis连接应由调用“setDefaultRedisConnectionParams”并传递一个字典{‘host’:‘hostname’,‘port’:6379,‘db’:0}来定义。

默认连接将连接到主机127.0.0.1,端口6379,数据库名为0。如果您没有明确定义这些字段中的任何一个,则将使用这些值用于相应的字段。

这些默认参数将用于所有模型,除非您在模型上定义了非空的REDIS_CONNECTION_PARAMS,则该模型将继承默认连接参数,覆盖任何在模型上定义的值。

如果您需要相同的模型连接到不同的Redis实例,可以调用“MyModel.connectAlt”(其中MyModel是您的模型类)并传递一个包含备用连接参数的字典。该函数将返回一个使用提供的备用连接的类的副本。

模型验证

该模型将在第一次实例化该类型的对象时进行验证。如果它的定义中有任何无效之处,将引发“InvalidModelException”。

用法

用法与Django或Flask非常相似。

查询

调用.filter或.filterInline构建一个查询/过滤集。使用下面描述的任何一种Fetch方法来执行查询。

objects = SomeModel.objects.filter(param1=val).filter(param2=val).all()

数据库支持从等于和不等于的检索类型。要使用不等于表达式,将“__ne”追加到字段名的末尾。

objects = SomeModel.objects.filter(param1=val, param2__ne=val2).all()

所有过滤器都在Redis服务器上使用哈希查找应用。同一类型的所有过滤器(等于或不等于)在Redis上使用一个命令应用。因此,应用过滤器,无论有多少个过滤器,总共是1到2个命令。

过滤结果/客户端过滤

.all操作的结果是一个[QueryableList](https://pypi.python.org/pypi/QueryableList),包含了所有匹配的对象。每个对象类型与模型相同。你可以像使用普通列表一样使用QueryableList,但它可能更强大。

一旦从Redis中获取了结果,QueryableList允许你使用QueryableList支持的方式(例如gt、contains、in)进行进一步客户端过滤。

示例

mathTeachers = People.objects.filter(job='Math Teacher').all()

experiencedMathTeachers = mathTeachers.filter(experienceYears__gte=10) # 获取具有10年或以上经验的数学教师

cheeseLovingMathTeachers = matchTeachers.filter(likes__splitcontains=(' ', 'cheese')) # 检查空格分隔的列表字段'likes'是否包含'cheese'

更多信息请见 https://github.com/kata198/QueryableList

保存

obj = SomeModel(field1='value', field2='value') obj.save()

使用过滤器删除

SomeModel.objects.filter(name='Bad Man').delete()

删除单个对象

obj.delete()

原子数据集替换

还有一个名为“reset”的强大方法,可以原子性地替换属于该模型的所有元素。这对于缓存替换等非常有用。

lst = [SomeModel(…), SomeModel(..)]

SomeModel.reset(lst)

例如,你可以有一个SQL后端和cron作业,执行复杂查询(或仅获取相同的模型),并每5分钟进行一次原子替换,以在应用中获得巨大的性能提升。

通过SomeModel.objects.filter(key=val, key2=val2)过滤对象并使用.all获取对象

示例:SomeModel.objects.filter(name='Tim', colour='purple').filter(number=5).all()

获取主键

有时你可能想要通过外键关系引用单个对象,或者为了更快/更独特地检索,而不是过滤。

每个保存的对象都有一个唯一的唯一主键(每个模型都是唯一的),可以通过“getPk”方法检索。然后你可以使用此值在exists、get、getMultiple等方法中使用。

获取函数:

构建过滤器集不会实际获取任何数据,直到调用以下其中一个(请参阅API以获取完整列表)。所有这些函数都作用于当前的过滤器集。

示例:matchingObjects = SomeModel.objects.filter(…).all()

all - 返回匹配此过滤器的所有对象

allOnlyFields - 接受字段列表,并仅使用当前过滤器集获取这些字段

allByAge - 返回匹配此过滤器的对象,按从旧到新的顺序排列

delete - 删除匹配此过滤器的对象

count - 获取匹配此过滤器的对象数量

first - 获取当前过滤器下的最旧记录

last - 获取当前过滤器下的最新记录

random - 获取当前过滤器下的随机元素

getPrimaryKeys - 获取与当前过滤器关联的主键

过滤器函数

这些函数向当前集添加过滤器。“filter”返回一个副本,“filterInline”作用于该对象。

filter - 添加额外的过滤器,返回过滤器对象的副本(moreFiltered = filtered.filter(key2=val2))

filterInline - 向当前过滤器对象添加额外的过滤器。

全局获取函数

这些函数在SomeModel.objects上可用,不使用任何过滤器(它们获取特定对象)

get - 通过pk获取单个对象

getMultiple - 通过pk列表获取多个对象

exists - 测试给定pk下是否存在对象

模型函数

实际对象包含包括

save - 保存此对象(如果不存在则创建,否则更新)

delete - 删除此对象

getUpdatedFields - 查看上次获取后的更改

更新索引

随着模型的变化,你可能需要向INDEXED_FIELDS数组中添加字段。如果这是一个已存在的字段,你可以通过以下方式重新索引模型:

MyModel.objects.reindex()

然而,如果你更改了可索引字段的字段类型,你应该使用“reset”方法。

MyModel.objects.reset(MyModel.objects.all())

连接到多个Redis实例

您可能想在多个Redis实例上使用相同的模型。要做到这一点,请在IndexedRedisModel上使用.connectAlt方法。

AltConnectionMyModel = MyModel.connectAlt({'host' : 'althost', 'db' : 4})

“connectAlt”方法接受一个Redis连接参数的字典,并返回一个指向备用Redis的Model的副本。

您可以使用AltConnectionMyModel就像使用MyModel一样。

客户端过滤/方法

在从redis检索了一组对象之后(例如通过调用.all()),您将获得一个已检索对象的IRQueryableList。

这是一个智能列表,它封装了QueryableList(https://github.com/kata198/QueryableList)并允许使用多种更高级的过滤(包含、不区分大小写的比较、分割过滤等)。有关所有可用操作的详细信息,请参阅QueryableList文档。

这些操作将在获取后作用于对象,但有时您需要过滤超出简单的等于或不等于,这是Redis后端的当前限制。

您可以使用链式调用

# 从Redis获取所有field1等于“something”的对象。

# 然后,在客户端,过滤出csvData不为空且以逗号分割包含“someItem”作为元素的对象。

# 然后,仍然在客户端,过滤出(状态为“pending”或“saved”)或lastUpdated小于或等于700秒前的对象。

#(请注意,确保lastUpdated是IRField(..valueType=int)或float,否则您将比较字符串)

myObjects = MyModel.objects.filter(field1='something').all().filter(csvData__isnull=False, csvData__splitcontains=("," , "someItem")).filterOr(status__in=('pending', 'saved'), lastUpdated__lte(time.time() - 700))

IRQueryableList上的其他方法包括

  • getModel - 返回与这些对象关联的模型

  • delete - 删除此列表中的所有对象。

    注意:这样做更有效率

    MyModel.objects.filter(…).delete()

    而不是这样做

    MyModel.objects.filter(…).all().delete()

    因为后者实际上检索了完整对象,然后删除它们,而前者只删除匹配项。

    然而,有时您可能希望在删除之前在客户端进行额外的过滤,这支持这一点。

  • save - 保存此列表中的所有对象。如果是所有现有对象,则仅更新自获取以来已更改的字段。

  • reload - 逐个重新加载此列表中的所有对象。这将从Redis获取最新数据并将其应用到项目上。

    此函数的返回将是一个与IRQueryableList相同索引的列表。项目将是KeyError异常(如果项目在Redis端被删除),或包含字段更新字典,键为字段名称,值为(旧值,新值)元组。

  • refetch - 再次检索此列表中的所有对象,并返回一个新的IRQueryableList。请注意,这不会再次执行过滤,而是基于每个项目的内部主键检索每个项目。

排序

在获取结果后,您可以通过在IRQueryableList上调用.sort_by来对它们进行排序。

示例

myObjs = MyModel.objects.filter(blah='something').all().sort_by('startDate')

编码

IndexedRedis默认使用系统默认编码(sys.getdefaultencoding),除非它是ascii,在这种情况下将默认使用utf-8。

您可以通过IndexedRedis.setDefaultIREncoding来更改此设置。

要获取当前默认编码,请使用IndexedRedis.getDefaultIREncoding。

要按字段使用不同的编码,请使用IRUnicodeField或IRBytesField,这两个类在构造时都接受一个“encoding”参数,允许您使数据遵循该编码。

更改

请参阅https://raw.githubusercontent.com/kata198/indexedredis/master/Changelog

示例

请参阅https://raw.githubusercontent.com/kata198/indexedredis/master/example.py

还可以查看

https://github.com/kata198/indexedredis/tree/master/tests

以了解各种独立和单元测试,这些测试将展示各种使用模式

联系我

请通过电子邮件与我联系,提出任何问题、错误,或者只是告诉我您在使用它!kata198@gmail.com

项目详情


下载文件

下载适用于您的平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。

源代码分发

indexedredis-6.0.3.tar.gz (198.9 kB 查看哈希值)

上传时间 源代码

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页