跳转到主要内容

RedisSearch Python客户端

项目描述

license PyPI version CircleCI GitHub issues Codecov Known Vulnerabilities Total alerts

RediSearch Python客户端

Forum Discord

弃用通知

redis-py 4.0.0开始,此库已弃用。其功能已合并到redis-py中。请从pypy安装它从存储库安装。


这是一个利用RediSearch Redis模块 API的Python搜索引擎库。

它是RediSearch的“官方”客户端,应被视为其标准客户端实现。

功能

RediSearch是一个开源(RSAL)、高性能的搜索引擎,作为Redis模块实现。它使用自定义数据类型,允许在Redis内部进行快速、稳定且功能丰富的全文搜索。

此客户端是RediSearch API协议的包装器,允许您轻松利用其功能。

RediSearch的功能包括

  • 文档中多个字段的全文索引。
  • 增量索引而不会损失性能。
  • 文档排名(由用户在索引时手动提供)和字段权重。
  • 自动完成建议(具有模糊前缀建议)。
  • 精确短语搜索。
  • 在多种语言中基于词干提取的查询扩展(使用Snowball)。
  • 限制搜索到特定文档字段(支持最多8个字段)。
  • 数字过滤和范围。
  • 自动索引现有的HASH键作为文档。

更多详细信息,请访问http://redisearch.io

示例

创建客户端实例

创建redisearch-py客户端实例时,唯一必需的参数是索引的名称。

from redisearch import Client

client = Client("my-index")

要使用用户名和/或密码连接,将这些选项传递给客户端初始化器。

client = Client("my-index", password="my-password")

使用核心Redis命令

每个Client实例都包含一个redis-py Client实例。使用此对象运行核心Redis命令。

import datetime

from redisearch import Client

START_TIME = datetime.datetime.now().strftime("%Y-%m-%d-%H:%M.%S")

client = Client("my-index")

client.redis.set("start-time", START_TIME)

检查RediSearch索引是否存在

要检查RediSearch索引是否存在,请使用FT.INFO命令,如果索引不存在,则会引发ResponseError

from redis import ResponseError
from redisearch import Client

client = Client("my-index")

try:
    client.info()
except ResponseError:
    # Index does not exist. We need to create it!

定义搜索索引

使用IndexDefinition的实例来定义搜索索引。您只有在创建索引时才需要这样做。

RediSearch索引通过监视键前缀来跟踪Redis数据库中的Hash。如果一个以搜索索引配置的键前缀开头的Hash被添加、更新或从Redis中删除,RediSearch将在索引中做出相应的更改。您可以通过IndexDefinition初始化器的prefix参数来配置搜索索引的键前缀。

注意:一旦创建索引,RediSearch将在这些键的Hash更改时持续索引这些键。

IndexDefinition还接受一个模式。该模式指定从索引跟踪的Hash中索引哪些字段。字段类型是

  • TextField
  • TagField
  • NumericField
  • GeoField

有关这些字段类型含义的更多信息,请参阅RediSearch文档中的FT.CREATE命令。

在redisearch-py中,模式是Field实例的迭代器。一旦您有一个IndexDefinition实例,您可以通过将模式迭代器传递给create_index()方法来创建实例。

from redis import ResponseError
from redisearch import Client, IndexDefinition, TextField

SCHEMA = (
    TextField("title", weight=5.0),
    TextField("body")
)

client = Client("my-index")

definition = IndexDefinition(prefix=['blog:'])

try:
    client.info()
except ResponseError:
    # Index does not exist. We need to create it!
    client.create_index(SCHEMA, definition=definition)

索引文档

RediSearch 2.0索引持续跟踪您定义的键前缀的Hash,因此如果您想将文档添加到索引中,您只需创建一个具有这些前缀之一的Hash。

# Indexing a document with RediSearch 2.0.
doc = {
    'title': 'RediSearch',
    'body': 'Redisearch adds querying, indexing, and full-text search to Redis'
}
client.redis.hset('doc:1', mapping=doc)

RediSearch的旧版本要求您调用add_document()方法。此方法已弃用,但为了参考,我们在此处包含其用法。

# Indexing a document for RediSearch 1.x
client.add_document(
    "doc:2",
    title="RediSearch",
    body="Redisearch implements a search engine on top of redis",
)

查询

基本查询

使用search()方法执行基本全文和字段特定搜索。此方法不包含RediSearch FT.SEARCH命令中可用的许多选项--请参阅本文档后面的“构建复杂查询”部分,了解如何使用这些选项。

res = client.search("evil wizards")

结果对象

结果被包装在包含结果数量和匹配文档列表的Result对象中。

>>> print(res.total)
2
>>> print(res.docs[0].title)
"Wizard Story 2: Evil Wizards Strike Back"

构建复杂查询

您可以使用Query对象构建复杂查询

q = Query("evil wizards").verbatim().no_content().with_scores().paging(0, 5)
res = client.search(q)

有关这些选项的解释,请参阅RediSearch文档中的FT.SEARCH命令。

查询语法

查询的默认行为是在索引中的所有TEXT字段上执行全文搜索,以匹配查询中所有术语的交集。

因此,本README“基本查询”部分中给出的示例client.search("evil wizards")将在所有TEXT字段中搜索“邪恶”和“巫师”的交集。

然而,可能的查询类型还有很多!传递给search()方法或Query()初始化器的字符串具有RediSearch中可用的完整查询语法。

例如,对索引中特定 TEXT 字段的全文搜索如下所示

# Full-text search
res = client.search("@title:evil wizards")

查找2020年或2021年出版的书籍如下所示

client.search("@published_year:[2020 2021]")

想了解更多信息,请参阅RediSearch查询语法文档

聚合查询

该库包含一个程序接口,用于运行RediSearch的聚合查询

制作聚合查询

要制作聚合查询,请将AggregateRequest类的实例传递给Client实例的search()方法。

例如,查找单一年度出版书籍最多的情况如下所示

from redisearch import Client
from redisearch import reducers
from redisearch.aggregation import AggregateRequest

client = Client('books-idx')

request = AggregateRequest('*').group_by(
    '@published_year', reducers.count().alias("num_published")
).group_by(
    [], reducers.max("@num_published").alias("max_books_published_per_year")
)

result = client.aggregate(request)

redis-cli等价查询

上面给出的聚合查询相当于在redis-cli中直接输入以下FT.AGGREGATE命令

FT.AGGREGATE books-idx *
    GROUPBY 1 @published_year
      REDUCE COUNT 0 AS num_published
    GROUPBY 0
      REDUCE MAX 1 @num_published AS max_books_published_per_year

聚合结果对象

聚合查询返回一个包含查询返回的行和一个游标的AggregateResult对象,如果您正在使用游标API

from redisearch.aggregation import AggregateRequest, Asc

request = AggregateRequest('*').group_by(
    ['@published_year'], reducers.avg('average_rating').alias('average_rating_for_year')
).sort_by(
    Asc('@average_rating_for_year')
).limit(
    0, 10
).filter('@published_year > 0')

...


In [53]: resp = c.aggregate(request)
In [54]: resp.rows
Out[54]:
[['published_year', '1914', 'average_rating_for_year', '0'],
 ['published_year', '2009', 'average_rating_for_year', '1.39166666667'],
 ['published_year', '2011', 'average_rating_for_year', '2.046'],
 ['published_year', '2010', 'average_rating_for_year', '3.125'],
 ['published_year', '2012', 'average_rating_for_year', '3.41'],
 ['published_year', '1967', 'average_rating_for_year', '3.603'],
 ['published_year', '1970', 'average_rating_for_year', '3.71875'],
 ['published_year', '1966', 'average_rating_for_year', '3.72666666667'],
 ['published_year', '1927', 'average_rating_for_year', '3.77']]

减少器函数

从示例中可以看出,我们使用了reducers模块中的一个对象。有关在使用分组结果时可以使用的减少器函数的更多示例,请参阅RediSearch文档

减少器函数包括一个alias()方法,该方法为减少器结果赋予一个特定的名称。如果您不提供名称,RediSearch将生成一个。

按零、一个或多个字段分组

group_by语句可以接受一个字段名称作为字符串,也可以接受多个字段名称作为字符串列表。

AggregateRequest('*').group_by('@published_year', reducers.count())

AggregateRequest('*').group_by(
    ['@published_year', '@average_rating'],
    reducers.count())

要对聚合查询的每个结果运行减少器函数,请将空列表传递给group_by(),这在redis-cli中编写聚合查询时相当于传递选项GROUPBY 0

AggregateRequest('*').group_by([], reducers.max("@num_published"))

注意:聚合查询至少需要一个group_by()方法调用。

排序和限制

使用AggregateRequest实例,您可以使用sort_by()方法进行排序,并使用limit()方法进行限制。

例如,查找每年出版书籍的平均评分,按年度平均评分排序,并仅返回前十个结果

from redisearch import Client
from redisearch.aggregation import AggregateRequest, Asc

c = Client()

request = AggregateRequest('*').group_by(
    ['@published_year'], reducers.avg('average_rating').alias('average_rating_for_year')
).sort_by(
    Asc('@average_rating_for_year')
).limit(0, 10)

c.aggregate(request)

注意limit()的第一个选项是零基偏移量,第二个选项是要返回的结果数量。

过滤

使用过滤在减少器函数运行后拒绝聚合查询的结果。例如,计算每年出版书籍的平均评分,并仅返回平均评分高于3的年份

from redisearch.aggregation import AggregateRequest, Asc

req = AggregateRequest('*').group_by(
    ['@published_year'], reducers.avg('average_rating').alias('average_rating_for_year')
).sort_by(
    Asc('@average_rating_for_year')
).filter('@average_rating_for_year > 3')

安装

  1. 安装RediSearch
  2. 安装Python客户端
$ pip install redisearch

开发

  1. 创建一个虚拟环境来管理您的Python依赖项,并确保它已激活。virtualenv -v venv
  2. 安装pypoetry以管理您的依赖项。pip install --user poetry
  3. 安装依赖项。poetry install

注意:由于与python 3.10的交互,您可能需要运行以下命令,如果在安装包时收到JSONError。

poetry config experimental.new-installer false

测试

可以使用Docker轻松进行测试。运行以下命令

make -C test/docker test PYTHON_VER=3

(将PYTHON_VER=3替换为PYTHON_VER=2以使用Python 2.7进行测试。)

或者,使用以下步骤

首先,运行

PYTHON_VER=3 ./test/test-setup.sh

这将在一个名为venv3的Python虚拟环境中设置一个Python虚拟环境(如果使用PYTHON_VER=2,则是在venv2中)。

之后,以守护进程方式在一个容器中运行RediSearch

docker run -d -p 6379:6379 redislabs/redisearch:2.0.0

最后,调用虚拟环境并运行测试

. ./venv3/bin/activate
REDIS_PORT=6379 python test/test.py
REDIS_PORT=6379 python test/test_builder.py

项目详情


下载文件

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

源分发

redisearch-2.1.1.tar.gz (29.7 kB 查看哈希值)

上传时间

构建分发

redisearch-2.1.1-py3-none-any.whl (26.8 kB 查看哈希值)

上传时间 Python 3

由以下机构支持