13 个版本 (破坏性更新)
0.10.0 | 2022年10月20日 |
---|---|
0.8.0 | 2022年5月30日 |
0.7.0 | 2021年12月24日 |
0.6.0 | 2021年5月28日 |
0.2.0 | 2020年7月31日 |
#1806 in 数据库接口
72KB
1.5K SLoC
parse-mediawiki-sql
这是一个用于快速解析来自 Wikimedia 导出 的 SQL 文件的库。它经常与来自英语 Wiktionary 导出的某些文件一起使用,但也应该适用于其他维基的导出。
背景
维基媒体提供可以由数据库服务器执行的 SQL 文件,以创建各种 MediaWiki 数据库表 的副本。但执行创建一些大表的脚本非常慢,而对于重复性工作,运行一个通过解析脚本提取信息的程序会快得多。例如,解析所有 page.sql
的 template_redirects
示例程序大约需要 20 秒,而使用 mariadb
执行 page.sql
创建 page
表 需要更长的时间,我尝试的时候超过了一个小时。
这个库某种程度上是我之前 Lua 库(parse_sql_dump
)的改写,而那个库又受到WikiUtils 的启发,一个链接到维基百科帮助页面 的库,它使用正则表达式解析 SQL 文件。我的 Lua 库使用 LPeg(我非常喜欢)解析文件。像 Rust 库一样,它有一个迭代器接口,但当我用它解析 page.sql
时,它经常消耗我微薄的 RAM 供应,导致我的计算机进入交换空间并出现故障,不得不重启。
因此,我最终创建了一个更节省内存的 Rust 库。在 Rust 中,通过让解析器的输出从输入借用,可以相对容易地最小化解析器的内存使用。使用内存映射,操作系统处理分配和释放解析器输入的内存。
库
入口点是 iterate_sql_insertions
,它接收一个 SQL 脚本字节数组切片(&[u8]
)并生成一个结构体,该结构体作为表示 INSERT
语句中的行的结构体的迭代器。这些结构体位于 parse_mediawiki_sql::schemas
中,它们的字段类型可以在 parse_mediawiki_sql::types
中找到。从 iterate_sql_insertions
生成的结构体从字节数组切片中借用,因此在 for
循环中必须作为可变引用进行迭代:for _ in &mut parse_mediawiki_sql::iterate_sql_insertions(&sql_script_byte_slice) { /* ... */ }
。
结构体字段的名称基于数据库表中的字段名称,但去除了前缀。同一表中与另一表中的字段相关的字段使用相同的数据类型,并且数据库中为 int
或 binary
类型的几个字段由更具体的 Rust 类型表示。
例如,Page
结构体表示 page
表中的一行。其字段 id
、namespace
和 title
(其类型分别是 PageId
、PageNamespace
和 PageTitle
))表示 page_id
、page_namespace
和 page_title
字段。在 Redirect
结构体中的 from
字段(表示 rd_from
)引用了由其 page_id
字段标识的 page
表中的一行,因此它同样是一个 PageId
。
如果可能,字段将从输入中借用。如果一个 binary
类型包含有效的 UTF-8,它将表示为 String
或 &str
,否则表示为一个 Vec<u8>
。如果一个 binary
字段是有效的 UTF-8 并且不会包含任何转义(如 \'
),则将其解析为从输入 &[u8]
借用的 &str
。
由于一些SQL转储文件,如page.sql
,可能非常大,我使用了一个便利函数来将文件内存映射,以避免将其完全读入内存,并为迭代器的项目提供借用的东西。示例使用utils::memory_map
(由功能utils
启用),该功能使用memmap
存储库,但具有更友好的错误类型。
示例
生成包含所有重定向页面标题的Vec
use parse_mediawiki_sql::{
iterate_sql_insertions,
schemas::Page,
field_types::{PageNamespace, PageTitle},
utils::memory_map,
};
use std::fs::File;
let page_sql = unsafe { memory_map("page.sql")? };
let redirects: Vec<(PageNamespace, PageTitle)> =
iterate_sql_insertions(&page_sql)
.filter_map(
|Page { namespace, title, is_redirect, .. }| {
if is_redirect {
Some((namespace, title))
} else {
None
}
},
)
.collect();
当前用途
template_redirect
示例,可以使用以下命令运行: cargo run --release --example template_redirect path/to/page.sql path/to/redirect.sql > template_redirects.json
,生成一个JSON对象,其中包含特定转储版本的所有模板重定向。此程序在Toolforge上的Templatehoard 工具中使用,该工具提供来自英语维基词典的模板实例的转储文件,包括模板及其重定向。
待办事项
- 允许解析直接提供的
.sql.gz
文件(目前,它们必须先解压) - 在
parse_sql_insertions
返回的迭代器中获得更友好的错误。 - 检查迭代器是否解析了整个SQL插入集。
依赖关系
~2.5–3.5MB
~58K SLoC