如果可以在 Postgres Python 存储过程或触发器中使用 NLTK,是否有人做过,甚至没有
1 回答
您可以在 PL/Python 存储过程或触发器中使用几乎任何 Python 库。
请参阅PL/Python 文档。
概念
要理解的关键点是PL/Python是CPython(无论如何,在 PostgreSQL 直到并包括 9.3);它使用与普通独立 Python 完全相同的解释器,它只是将其作为库加载到支持的 PostgreSQL 中。有一些限制(如下所述),如果它适用于 CPython,它适用于 PL/Python。
如果您的系统上安装了多个 Python 解释器 - 版本、发行版、32 位与 64 位等 - 您可能需要确保在运行 distutils 脚本等时将扩展和库安装到正确的解释器中,但仅此而已关于它。
由于您可以加载系统 Python 可用的任何库,因此没有理由认为 NLTK 会成为问题,除非您知道它需要诸如线程之类的东西,而 PostgreSQL 后端并不真正推荐它。(果然,我试过了,它“刚刚好”,见下文)。
一个可能的担忧是,像 NLTK 之类的启动开销可能非常大,您可能希望在 postmaster 中预加载 PL/Python 并在设置代码中导入模块,以便在后端启动时准备好。了解 postmaster 是所有其他后端的父进程fork()
,因此如果 postmaster 预加载某些内容,则后端可以使用它,从而大大减少开销。无论哪种方式都可以测试性能。
安全
因为您可以通过 PL/Python 加载任意 C 库,并且因为 Python 解释器没有真正的安全模型,plpythonu
所以它是一种“不受信任”的语言。脚本作为用户可以完全且不受限制地访问系统,postgres
并且可以相当简单地绕过 PostgreSQL 中的访问控制。出于明显的安全原因,这意味着 PL/Python 函数和触发器只能由超级用户创建,尽管对于GRANT
普通用户来说,运行由超级用户安装的精心编写的函数是相当合理的。
好处是您几乎可以在普通 Python 中做任何事情,请记住 Python 解释器的生命周期是数据库连接(会话)的生命周期。不建议使用线程,但大多数其他事情都很好。
PL/Python 函数必须在编写时仔细输入卫生,search_path
在调用 SPI 以运行查询时必须设置,等等。这在手册中有更多讨论。
限制
长时间运行或可能有问题的事情,如 DNS 查找、与远程系统的 HTTP 连接、SMTP 邮件传递等,通常应使用帮助脚本LISTEN
而NOTIFY
不是后端作业来完成,以保持 PostgreSQL 的性能并避免VACUUM
大量阻碍的长交易。你可以在后端做这些事情,这不是一个好主意。
您应该避免在 PostgreSQL 后端创建线程。
不要尝试加载任何会加载libpq
C 库的 Python 库。这可能会导致后端出现各种令人兴奋的问题。从 PL/Python 与 PostgreSQL 对话时,使用 SPI 例程而不是常规客户端库。
不要在后端做很长时间运行的事情,你会导致真空问题。
不要加载任何可能加载已加载的本机 C 库的不同版本的任何内容——比如不同的 libcrypto、libssl 等。
永远不要直接写入 PostgreSQL 数据目录中的文件。
PL/Python 函数postgres
在操作系统上以系统用户身份运行,因此它们无权访问用户的主目录或连接客户端上的文件等内容。
测试结果
$ yum install python-nltk python-nltk
$ psql -U postgres regress
regress=# CREATE LANGUAGE plpythonu;
regress=# CREATE OR REPLACE FUNCTION nltk_word_tokenize(word text) RETURNS text[] AS $$
import nltk
return nltk.word_tokenize(word)
$$ LANGUAGE plpythonu;
regress=# SELECT nltk_word_tokenize('This is a test, it''s going to work fine');
nltk_word_tokenize
-----------------------------------------------
{This,is,a,test,",",it,'s,going,to,work,fine}
(1 row)
所以,正如我所说:试试吧。只要 PostgreSQL 用于 plpython 的 Python 解释器安装了 nltk 的依赖项,它就可以正常工作。
笔记
PL/Python 是 CPython,但我希望看到一个基于 PyPy 的替代方案,它可以使用 PyPy 的沙盒功能运行不受信任的代码。