我希望能够在我的 SQLAlchemy 映射对象之一的多个文本字段中进行全文搜索。我还希望我的映射对象支持外键和事务。
我打算使用MySQL来运行全文搜索。但是,据我所知,MySQL只能在MyISAM表上运行全文搜索,不支持事务和外键。
为了实现我的目标,我计划创建两个表。我的代码看起来像这样:
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(50))
description = Column(Text)
users_myisam = Table('users_myisam', Base.metadata,
Column('id', Integer),
Column('name', String(50)),
Column('description', Text),
mysql_engine='MyISAM')
conn = Base.metadata.bind.connect()
conn.execute("CREATE FULLTEXT INDEX idx_users_ftxt \
on users_myisam (name, description)")
然后,为了搜索,我将运行以下命令:
q = 'monkey'
ft_search = users_myisam.select("MATCH (name,description) AGAINST ('%s')" % q)
result = ft_search.execute()
for row in result: print row
这似乎有效,但我有几个问题:
我创建两个表来解决我的问题的方法合理吗?有没有标准/更好/更干净的方法来做到这一点?
是否有 SQLAlchemy 方法来创建全文索引,或者我最好像上面那样直接执行“CREATE FULLTEXT INDEX ...”?
看起来我在搜索/匹配查询时遇到了 SQL 注入问题。我该如何选择“SQLAlchemy 方式”来解决这个问题?
有没有一种干净的方法将 users_myisam 选择/匹配加入到我的用户表并返回实际的 User 实例,因为这是我真正想要的?
为了使我的users_myisam表与我的映射对象用户表保持同步,对我来说在我的User类上使用MapperExtension并设置before_insert、before_update和before_delete方法来适当更新users_myisam表是否有意义,或者有更好的方法来实现这个吗?
谢谢, 迈克尔
我创建两个表来解决我的问题的方法合理吗? 有没有标准/更好/更干净的方法来做到这一点?
我以前没有见过这种用例尝试,因为重视事务和约束的开发人员倾向于首先使用 Postgresql。 我知道这在您的具体情况下可能是不可能的。
是否有 SQLAlchemy 方法来创建全文索引,或者我最好 像我上面那样直接执行“CREATE FULLTEXT INDEX ...”?
conn.execute() 很好,但如果你想要更集成的东西,你可以使用 DDL() 构造,通读 http://docs.sqlalchemy.org/en/rel_0_8/core/schema.html?highlight= ddl#customizing-ddl 了解详情
看起来我在搜索/匹配查询时遇到 SQL 注入问题。我该怎么做 选择“SQLAlchemy 方式”来解决这个问题?
注意:此配方仅用于MATCH
同时针对多列 - 如果您只有一列,请更简单地使用match() 运算符。 基本上你可以使用 text() 结构:
from sqlalchemy import text, bindparam
users_myisam.select(
text("MATCH (name,description) AGAINST (:value)",
bindparams=[bindparam('value', q)])
)
您可以更全面地定义自定义构造:
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import ClauseElement
from sqlalchemy import literal
class Match(ClauseElement):
def __init__(self, columns, value):
self.columns = columns
self.value = literal(value)
@compiles(Match)
def _match(element, compiler, **kw):
return "MATCH (%s) AGAINST (%s)" % (
", ".join(compiler.process(c, **kw) for c in element.columns),
compiler.process(element.value)
)
my_table.select(Match([my_table.c.a, my_table.c.b], "some value"))
文档:
http://docs.sqlalchemy.org/en/rel_0_8/core/compiler.html
有没有一种干净的方法来加入 users_myisam 选择/匹配右后卫 到我的用户表并返回实际的用户实例,因为这是我真正想要的?您可能应该创建一个 UserMyISAM 类,像 User 一样映射它,然后使用关系()将两个类链接在一起,然后可以进行像这样的简单操作:
query(User).join(User.search_table).\
filter(Match([UserSearch.x, UserSearch.y], "some value"))
为了使我的 users_myisam 表与我的映射对象保持同步 user 表,对我来说在我的表上使用 MapperExtension 有意义吗? 用户类,并设置before_insert、before_update和 before_delete 方法适当更新 users_myisam 表, 或者有更好的方法来实现这一点吗?MapperExtensions 已弃用,因此您至少需要使用
event API,并且在大多数情况下,我们希望尝试在刷新过程之外应用对象突变。 在这种情况下,我将使用 User 的构造函数,或者使用 init 事件,以及基本的 @validates 装饰器,它将接收 User 上目标属性的值并将这些值复制到 User.search_table
.总的来说,如果您从其他来源(例如 Oreilly 的书)学习 SQLAlchemy,它确实已经过时很多年了,我会专注于当前的在线文档。
是否有 SQLAlchemy 方法来创建全文索引,或者我最好像上面那样直接执行“CREATE FULLTEXT INDEX ...”?是的,如果您已经定义了
users_myisam
表声明式,就像您在问题中对
users
表所做的那样,您可以通过 SQLAlchemy 创建全文索引。通过 SQLAlchemy 的全文索引:
from sqlalchemy.schema import Index
Index("idx_users_ftxt", UsersMyisam.name, UsersMyisam.description, mysql_prefix="FULLTEXT")