创建大型XML文件的索引

0 投票
2 回答
996 浏览
提问于 2025-04-18 10:31

我有一个很大的bz2文件,里面是维基百科的文章,格式是xml。

从这个文件中提取文本并不难。我正在使用以下代码来解析xml。我想知道有没有办法在读取完原始的bz2或xml文件后,重新打开它并建立索引,这样我就可以把不同的行(比如“巴拉克·奥巴马”的文章)和那个索引关联起来,然后当需要某一行时,我可以直接找到它。

一种可能的方法是把bz2或xml文件拆分成更小的部分,然后对这些部分进行索引。有没有人有好的想法,如何尽快找到特定的行呢?

import bz2
try:
    from lxml import etree
except ImportError:
    import xml.etree.ElementTree as etree
import re


def _get_namespace(tag):
    namespace = re.match("^{(.*?)}", tag).group(1)
    if not namespace.startswith("http://www.mediawiki.org/xml/export-"):
        raise ValueError("%s not recognized as MediaWiki database dump"
                         % namespace)
    return namespace

def extract_pages(f):
    elems = (elem for _, elem in etree.iterparse(f, events=["end"]))
    elem = next(elems)

    namespace = _get_namespace(elem.tag)
    ns_mapping = {"ns": namespace}
    page_tag = "{%(ns)s}page" % ns_mapping
    text_path = "./{%(ns)s}revision/{%(ns)s}text" % ns_mapping
    id_path = "./{%(ns)s}id" % ns_mapping
    title_path = "./{%(ns)s}title" % ns_mapping
    for elem in elems:
        if elem.tag == page_tag:
            text = elem.find(text_path).text
            if text is None:
                continue
            yield (int(elem.find(id_path).text),
                   elem.find(title_path).text,
                   text)
            elem.clear()
            if hasattr(elem, "getprevious"):
                while elem.getprevious() is not None:
                    del elem.getparent()[0]

if __name__ == "__main__":
    dictionary={}
    f = bz2.BZ2File("simplewiki.xml.bz2", 'rb')

    for pageid, title, text in extract_pages(f):
        print pageid

2 个回答

0

一个XML文件并不是数据库……把它当成数据库用其实是一种错误的做法,而且在它上面加一些数据库功能,比如“索引”,只会让事情变得更糟。在我看来,bz2文件的内容是不能随机访问的。如果你需要数据库,最好把XML导入到一个数据库里。

对于大多数涉及XML数据的任务,mediawiki-utilities是最快的选择。为了举个例子,如果你想获取[[Barack Obama]]的文本,可以参考文档中的示例,前提是你已经下载了当前版本的XML数据:

from mw.xml_dump import Iterator

# Construct dump file iterator
dump = Iterator.from_file(open("example/dump.xml"))

# Iterate through pages
for page in dump:
    if page.title == "Barack Obama": continue
    # Iterate through a page's revisions
    for revision in page:

        print(revision.text)
1

如果你想在索引过的XML中进行高效搜索,最合适的工具就是XQuery。这是一种专门的语言,有很多快速的、带索引的数据库可以使用。你可以在Python中使用XQuery的接口,这样就能从你的Python程序中运行XQuery查询,但实际的查询语句还是要用XQuery来写,而不是Python。

和SQL数据库一样,XQuery数据库也有查询优化器,但你写查询的方式会影响索引的使用效率。你可以控制索引的方式,比如只索引ID属性,或者使用完整文本索引(包括词干处理),还有很多其他选择。

如果你想找一个开源的XQuery数据库,并且希望有好的可视化支持来帮助你编写和调试代码,可以考虑BaseX。它的用户界面非常友好,并且紧跟语言规范的最新动态,不断添加新功能。还有一个维护得不错的开源XQuery数据库是eXist,而MarkLogic则是一个备受尊重的商业XQuery实现。

如果你想从Python中运行查询,可以查看BaseX的可用客户端列表

另外,查看BaseX中关于索引的详细文档,确保你写的查询能够充分利用这些索引,并创建你需要的索引。

撰写回答