7

考虑到我的用户可以将数据保存为“café”或“cafe”,我需要能够使用不区分重音的查询在该字段上进行搜索。

我找到了https://github.com/djcoin/django-unaccent/,但我不知道是否可以在 sqlalchemy 上实现类似的东西。

我正在使用 PostgreSQL,所以如果解决方案是特定于这个数据库的,对我有好处。如果是通用解决方案,那就更好了。

谢谢你的帮助。

4

2 回答 2

12

首先在 PostgreSQL 中安装 unaccess 扩展:create extension unaccent;

接下来,unaccent在 Python 中声明 SQL 函数:

from sqlalchemy.sql.functions import ReturnTypeFromArgs

class unaccent(ReturnTypeFromArgs):
    pass

并像这样使用它:

for place in session.query(Place).filter(unaccent(Place.name) == "cafe").all():
    print place.name

如果您有一个大表,请确保您有正确的索引,否则这将导致全表扫描。

于 2013-08-25T21:54:55.530 回答
8

一个简单且与数据库无关的解决方案是编写可以有两次重音的字段,一次有重音,一次没有重音。然后,您可以对非重音版本进行搜索。

要生成字符串的非重音版本,您可以使用Unidecode

要在插入或更新记录时自动将非重音版本分配给数据库,您可以在定义中使用defaultandonupdate子句。Column例如,使用 Flask-SQLAlchemy 你可以这样做:

from unidecode import unidecode
def unaccent(context):
    return unidecode(context.current_parameters['some_string'])

class MyModel(db.Model):
    id = Column(db.Integer, primary_key=True)
    some_string = db.Column(db.String(128))
    some_string_unaccented = db.Column(db.String(128), default=unaccent, onupdate=unaccent, index=True)

请注意我是如何只索引非重音字段的,因为这是将进行搜索的字段。

当然,在您可以搜索之前,您还必须取消您正在搜索的值。例如:

def search(text):
    return MyModel.query.filter_by(some_string_unaccented = unaccent(text)).all()

如有必要,您可以将相同的技术应用于全文搜索。

于 2013-08-25T21:52:26.717 回答