创建大型XML文件的索引
我有一个很大的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 个回答
一个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)
如果你想在索引过的XML中进行高效搜索,最合适的工具就是XQuery。这是一种专门的语言,有很多快速的、带索引的数据库可以使用。你可以在Python中使用XQuery的接口,这样就能从你的Python程序中运行XQuery查询,但实际的查询语句还是要用XQuery来写,而不是Python。
和SQL数据库一样,XQuery数据库也有查询优化器,但你写查询的方式会影响索引的使用效率。你可以控制索引的方式,比如只索引ID属性,或者使用完整文本索引(包括词干处理),还有很多其他选择。
如果你想找一个开源的XQuery数据库,并且希望有好的可视化支持来帮助你编写和调试代码,可以考虑BaseX。它的用户界面非常友好,并且紧跟语言规范的最新动态,不断添加新功能。还有一个维护得不错的开源XQuery数据库是eXist,而MarkLogic则是一个备受尊重的商业XQuery实现。
如果你想从Python中运行查询,可以查看BaseX的可用客户端列表。
另外,查看BaseX中关于索引的详细文档,确保你写的查询能够充分利用这些索引,并创建你需要的索引。