这个插件比名字类似的lua插件功能强大太多,不要装错。
存储库地址:https://github.com/alitrack/duckdb-luajit
1.安装插件
memory D force install luajit from community; memory D load luajit;2.拉取远程duckdb-luajit现成库(https://github.com/alitrack/duckdb-luajit-libs)
--列举可用模块 memory D SELECT * FROM luajit_module(mode := 'list_remote'); ┌─────────┬─────────────┬─────────────┬────────────────────┬────────────────────────────────────────────────┬──────────┐ │ ok │ mode │ phase │ message │ detail │ sql_name │ │ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │ ├─────────┼─────────────┼─────────────┼────────────────────┼────────────────────────────────────────────────┼──────────┤ │ true │ list_remote │ list_remote │ duckdb-luajit-libs │ available libs:\n dicom — libs/datasource/dic │ │ │ │ │ │ │ om.lua\n dirscan — libs/datasource/dirscan.lu │ │ │ │ │ │ │ a\n export — libs/export/export.lua\n json — │ │ │ │ │ │ │ libs/parser/json.lua\n base64 — libs/udf/bas │ │ │ │ │ │ │ e64.lua\n crc32 — libs/udf/crc32.lua\n uuid │ │ │ │ │ │ │ — libs/udf/uuid.lua\n html_escape — libs/udf/ │ │ │ │ │ │ │ html_escape.lua\n mcp_demo — libs/mcp/mcp-ser │ │ │ │ │ │ │ ver.sql\n │ │ └─────────┴─────────────┴─────────────┴────────────────────┴────────────────────────────────────────────────┴──────────┘ --拉取base64 udf memory D SELECT * FROM luajit_module(mode := 'install', sql_name := 'base64'); ┌─────────┬─────────┬─────────┬──────────────────────────────────────┬──────────────────────────────────────┬──────────┐ │ ok │ mode │ phase │ message │ detail │ sql_name │ │ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │ ├─────────┼─────────┼─────────┼──────────────────────────────────────┼──────────────────────────────────────┼──────────┤ │ true │ install │ install │ installed 'base64' (UDF) — cached at │ luajit_table('base64') or luajit_s(' │ base64 │ │ │ │ │ ~/.duckdb/luajit-libs/base64.lua │ base64', ...) │ │ └─────────┴─────────┴─────────┴──────────────────────────────────────┴──────────────────────────────────────┴──────────┘ --使用base64 udf成功 memory D SELECT luajit_s('base64', 'hello'); ┌─────────────────────────────┐ │ luajit_s('base64', 'hello') │ │ varchar │ ├─────────────────────────────┤ │ aGVsbG8= │ └─────────────────────────────┘错误的用法尝试
--希望安装mcp_demo,报错 memory D SELECT * FROM luajit_module(mode := 'install', sql_name := 'mcp_demo'); ┌─────────┬─────────┬─────────┬───────────────────────────────────────────────────────────────────┬─────────┬──────────┐ │ ok │ mode │ phase │ message │ detail │ sql_name │ │ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │ ├─────────┼─────────┼─────────┼───────────────────────────────────────────────────────────────────┼─────────┼──────────┤ │ false │ install │ │ install 'mcp_demo': [string "-- @lib: mcp_demo..."]:28: '=' expec │ │ mcp_demo │ │ │ │ │ ted near '*' │ │ │ └─────────┴─────────┴─────────┴───────────────────────────────────────────────────────────────────┴─────────┴──────────┘ --拉取sudoku失败,第一次是网络问题,第二次网络正常后,说不在索引中 memory D SELECT * FROM luajit_module(mode := 'install', sql_name := 'sudoku'); ┌─────────┬─────────┬─────────┬───────────────────────────────────────────────────────────────────┬─────────┬──────────┐ │ ok │ mode │ phase │ message │ detail │ sql_name │ │ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │ ├─────────┼─────────┼─────────┼───────────────────────────────────────────────────────────────────┼─────────┼──────────┤ │ false │ install │ │ install 'sudoku' failed: IO Error: Timeout was reached error for │ │ sudoku │ │ │ │ │ HTTP HEAD to 'https://raw.githubusercontent.com/alitrack/duckdb-l │ │ │ │ │ │ │ uajit-libs/main/INDEX' │ │ │ └─────────┴─────────┴─────────┴───────────────────────────────────────────────────────────────────┴─────────┴──────────┘ memory D SELECT * FROM luajit_module(mode := 'install', sql_name := 'sudoku'); ┌─────────┬─────────┬─────────┬──────────────────────────────────────────────────────────┬─────────┬──────────┐ │ ok │ mode │ phase │ message │ detail │ sql_name │ │ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │ ├─────────┼─────────┼─────────┼──────────────────────────────────────────────────────────┼─────────┼──────────┤ │ false │ install │ │ install 'sudoku' failed: lib 'sudoku' not found in INDEX │ │ sudoku │ └─────────┴─────────┴─────────┴──────────────────────────────────────────────────────────┴─────────┴──────────┘实地查看索引内容,确实不存在一个sudoku udf
ls ~/.duckdb/luajit-libs/ INDEX base64.lua mcp_demo.lua root@DESKTOP-59T6U68:/mnt/c/d# cat ~/.duckdb/luajit-libs/INDEX dicom|libs/datasource/dicom.lua dirscan|libs/datasource/dirscan.lua export|libs/export/export.lua json|libs/parser/json.lua base64|libs/udf/base64.lua crc32|libs/udf/crc32.lua uuid|libs/udf/uuid.lua html_escape|libs/udf/html_escape.lua mcp_demo|libs/mcp/mcp-server.sql考虑到国内上github.com经常网络出错,趁早把存储库整个下载到本地duckdb-luajit-libs-main目录下。
然后复制mcp-server.sql中的语句
-- 2. 注册 Lua UDF: 数独求解 (模块文件 sudoku.lua 需同目录, 或改用 install 协议从本仓库拉) memory D SELECT * FROM luajit_module(mode := 'compile', sql_name := 'sudoku_solve', source := 'local s = dofile(''duckdb-luajit-libs-main/libs/mcp/sudoku.lua'') return function(x) return s.solve(x) end'); ┌─────────┬─────────┬─────────┬─────────┬─────────┬──────────────┐ │ ok │ mode │ phase │ message │ detail │ sql_name │ │ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │ ├─────────┼─────────┼─────────┼─────────┼─────────┼──────────────┤ │ true │ compile │ compile │ OK │ │ sudoku_solve │ └─────────┴─────────┴─────────┴─────────┴─────────┴──────────────┘ memory D SELECT luajit_s('sudoku_solve', '000001002000020030004500600007600050080090006100005800001004000070900003400030020') AS r; ┌───────────────────────────────────────────────────────────────────────────────────┐ │ r │ │ varchar │ ├───────────────────────────────────────────────────────────────────────────────────┤ │ 359461782716829534824573619947682351583197246162345897631254978275918463498736125 │ └───────────────────────────────────────────────────────────────────────────────────┘ memory D .timer on memory D select count(*) from read_csv('sudoku17.txt'); ┌──────────────┐ │ count_star() │ │ int64 │ ├──────────────┤ │ 49150 │ └──────────────┘ Run Time (s): real 0.075 user 0.007009 sys 0.014781 memory D with a(i) as(select * from read_csv('sudoku17.txt') limit 3)select luajit_s('sudoku_solve',i)from a; ┌───────────────────────────────────────────────────────────────────────────────────┐ │ luajit_s('sudoku_solve', i) │ │ varchar │ ├───────────────────────────────────────────────────────────────────────────────────┤ │ 793684512486512937125973846932751684578246391641398725319465278857129463264837159 │ │ 673894512912735486845612973798261354526473891134589267469128735287356149351947628 │ │ 679835412123694758548217936416723895892561374735489621287956143961342587354178269 │ └───────────────────────────────────────────────────────────────────────────────────┘ Run Time (s): real 10.209 user 9.331371 sys 0.000000计算成功,速度不算太快,可能是算法过于简单原因。
李艳红先生将上述测试文档输入AI,AI自动找到了问题,并且修复了,顺便还升级了数独算法,用新的sudoku.lua重新编译一版sudoku_solve_opt函数,速度是上一版本的100倍。
testluaudf D SELECT * FROM luajit_module(mode := 'compile', sql_name := 'sudoku_solve_opt', source := 'local s = dofile(''./sudoku.lua'') return function(x) return s.solve(x) end'); ┌─────────┬─────────┬─────────┬─────────┬─────────┬──────────────────┐ │ ok │ mode │ phase │ message │ detail │ sql_name │ │ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │ ├─────────┼─────────┼─────────┼─────────┼─────────┼──────────────────┤ │ true │ compile │ compile │ OK │ │ sudoku_solve_opt │ └─────────┴─────────┴─────────┴─────────┴─────────┴──────────────────┘ testluaudf D with a(i) as(select * from read_csv('sudoku17.txt') limit 3)select luajit_s('sudoku_solve_opt',i)from a; ┌───────────────────────────────────────────────────────────────────────────────────┐ │ luajit_s('sudoku_solve_opt', i) │ │ varchar │ ├───────────────────────────────────────────────────────────────────────────────────┤ │ 793684512486512937125973846932751684578246391641398725319465278857129463264837159 │ │ 673894512912735486845612973798261354526473891134589267469128735287356149351947628 │ │ 679835412123694758548217936416723895892561374735489621287956143961342587354178269 │ └───────────────────────────────────────────────────────────────────────────────────┘ testluaudf D .timer on testluaudf D with a(i) as(from read_csv('sudoku17.txt') limit 3)select max(luajit_s('sudoku_solve_opt',i))from a; ┌───────────────────────────────────────────────────────────────────────────────────┐ │ max(luajit_s('sudoku_solve_opt', i)) │ │ varchar │ ├───────────────────────────────────────────────────────────────────────────────────┤ │ 793684512486512937125973846932751684578246391641398725319465278857129463264837159 │ └───────────────────────────────────────────────────────────────────────────────────┘ Run Time (s): real 0.071 user 0.015625 sys 0.000000 testluaudf D with a(i) as(from read_csv('sudoku17.txt') limit 300)select max(luajit_s('sudoku_solve_opt',i))from a; ┌───────────────────────────────────────────────────────────────────────────────────┐ │ max(luajit_s('sudoku_solve_opt', i)) │ │ varchar │ ├───────────────────────────────────────────────────────────────────────────────────┤ │ 986735124143298576275614893459183762821467359637529481592371648364852917718946235 │ └───────────────────────────────────────────────────────────────────────────────────┘ Run Time (s): real 5.289 user 5.234375 sys 0.031250又及,上个版本还存在lua自定义函数不能持久化的问题,现在也解决了。
到https://github.com/alitrack/duckdb-luajit/releases/tag/v0.32 下载离线版插件。强制安装并装载。
将内存数据库保存到物理数据库文件,再次打开此文件,load luajit;后,原来编译的lua自定义函数直接能用。
C:\d>duckdb155 -unsigned DuckDB v1.5.5 (Variegata) Enter ".help" for usage hints. memory D force install 'C:\Users\lt\Downloads\luajit.duckdb_extension'; memory D from duckdb_extensions(); ┌──────────────────┬─────────┬───────────┬───┬───────────────────┬───────────────────┬─────────────────────────────────┐ │ extension_name │ loaded │ installed │ … │ extension_version │ install_mode │ installed_from │ │ varchar │ boolean │ boolean │ … │ varchar │ varchar │ varchar │ ├──────────────────┼─────────┼───────────┼───┼───────────────────┼───────────────────┼─────────────────────────────────┤ │ luajit │ false │ true │ … │ v0.32 │ CUSTOM_PATH │ C:\Users\lt\Downloads\luajit.d… │ memory D load luajit; memory D SELECT * FROM luajit_module(mode := 'compile', sql_name := 'sudoku_solve', source := 'local s = dofile(''duckdb-luajit-libs-main/libs/mcp/sudoku.lua'') return function(x) return s.solve(x) end'); ┌─────────┬─────────┬─────────┬─────────┬─────────┬──────────────┐ │ ok │ mode │ phase │ message │ detail │ sql_name │ │ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │ ├─────────┼─────────┼─────────┼─────────┼─────────┼──────────────┤ │ true │ compile │ compile │ OK │ │ sudoku_solve │ └─────────┴─────────┴─────────┴─────────┴─────────┴──────────────┘ memory D SELECT luajit_s('sudoku_solve', '000001002000020030004500600007600050080090006100005800001004000070900003400030020') AS r; ┌───────────────────────────────────────────────────────────────────────────────────┐ │ r │ │ varchar │ ├───────────────────────────────────────────────────────────────────────────────────┤ │ 359461782716829534824573619947682351583197246162345897631254978275918463498736125 │ └───────────────────────────────────────────────────────────────────────────────────┘ memory D ATTACH 'lua032.db'; memory D COPY FROM DATABASE memory to lua032; memory D .exit C:\d>duckdb155 lua032.db -unsigned DuckDB v1.5.5 (Variegata) Enter ".help" for usage hints. lua032 D load luajit; lua032 D SELECT luajit_s('sudoku_solve', '000001002000020030004500600007600050080090006100005800001004000070900003400030020') AS r; ┌───────────────────────────────────────────────────────────────────────────────────┐ │ r │ │ varchar │ ├───────────────────────────────────────────────────────────────────────────────────┤ │ 359461782716829534824573619947682351583197246162345897631254978275918463498736125 │ └───────────────────────────────────────────────────────────────────────────────────┘