我如何有效地尝试在大量 XML 列表中查找大量单词
How do I efficiently try to find a large list of words in a large list of XMLs
我有一大堆化学名称 (~30,000,000) 和一大堆文章 (~34,000) 以 XML 的形式存储在服务器上作为文件。
我正在尝试将每个 XML 解析为提及一个或多个化学名称的字符串。最终结果将是一个制表符分隔的文本文件,其中我有一个文件名,然后是文件中出现的化学品列表。
当前的问题是我有一个 for 循环,它循环遍历所有 XML 的 for 循环内的所有化学品。嵌套在 for 循环中的是 python 中的 string in string
操作。有什么方法可以通过使用比 string in string
更有效的操作或重新排列 for 循环来提高性能?
我的伪代码:
for article is articles:
chemicals_in_article = []
temp_article = article.lower()
for chemical in chemicals:
if chemical in temp_article: chemicals_in_article.append(chemical)
#Write the results into a text file
output_file.write(article.file_name)
for chemical in chemicals_in_article:
output_file.write("\t" + chemical)
output_file.write("\n")
签出 regex
报表。它们有时可能比 string in string
更快。尝试使用它们有一点学习曲线。
检查 以获取一些线索。
我不确定 30M 条目是否会破坏您的记忆,但基于 trie 的方法可能是最快的。有几个包以稍微不同的形式实现了这一点,例如 FlashText; or trieregex。两者都有与您的场景完全匹配的示例。
编辑:...至少在纯文本上。根据上面的评论,如果您想避免匹配标记的随机位,请构建一个 trie,然后使用 XPath matches
函数查找 trie 派生的正则表达式找到匹配项的文本节点。不幸的是,Python 的主要 XML 库不支持 matches
(实际上支持 XPath 2.0 的库很少),所以这不是很可行。
由于您只需要检测文档文本中任何位置是否存在关键字,一个可行的解决方法是将 XML 转换为文本,然后使用上述方法之一。这是一个例子:
#pip install libxml2-python3 trieregex
from trieregex import TrieRegEx as TRE
from libxml2 import parseDoc
import re
# prepare
words = ['lemon', 'lemons', 'lime', 'limes', 'pomelo', 'pomelos', 'orange', 'oranges', 'citrus', 'citruses']
tre = TRE(*words)
pattern = re.compile(fr"\b{tre.regex()}\b")
# => \b(?:l(?:emons?|imes?)|citrus(?:es)?|oranges?|pomelos?)\b
# search
xml = """
<?xml version="1.0"?>
<recipe>
<substitute for="lemon">three limes</substitute>
<substitute for="orange">pomelo</substitute>
</recipe>
""".strip()
doc = parseDoc(xml)
text = doc.getContent()
matches = pattern.findall(text)
print(matches)
# => ['limes', 'pomelo']
doc.freeDoc()
请注意,您只需要准备一次正则表达式;然后您可以在多个文档上快速应用它。
我有一大堆化学名称 (~30,000,000) 和一大堆文章 (~34,000) 以 XML 的形式存储在服务器上作为文件。
我正在尝试将每个 XML 解析为提及一个或多个化学名称的字符串。最终结果将是一个制表符分隔的文本文件,其中我有一个文件名,然后是文件中出现的化学品列表。
当前的问题是我有一个 for 循环,它循环遍历所有 XML 的 for 循环内的所有化学品。嵌套在 for 循环中的是 python 中的 string in string
操作。有什么方法可以通过使用比 string in string
更有效的操作或重新排列 for 循环来提高性能?
我的伪代码:
for article is articles:
chemicals_in_article = []
temp_article = article.lower()
for chemical in chemicals:
if chemical in temp_article: chemicals_in_article.append(chemical)
#Write the results into a text file
output_file.write(article.file_name)
for chemical in chemicals_in_article:
output_file.write("\t" + chemical)
output_file.write("\n")
签出 regex
报表。它们有时可能比 string in string
更快。尝试使用它们有一点学习曲线。
检查
我不确定 30M 条目是否会破坏您的记忆,但基于 trie 的方法可能是最快的。有几个包以稍微不同的形式实现了这一点,例如 FlashText; or trieregex。两者都有与您的场景完全匹配的示例。
编辑:...至少在纯文本上。根据上面的评论,如果您想避免匹配标记的随机位,请构建一个 trie,然后使用 XPath matches
函数查找 trie 派生的正则表达式找到匹配项的文本节点。不幸的是,Python 的主要 XML 库不支持 matches
(实际上支持 XPath 2.0 的库很少),所以这不是很可行。
由于您只需要检测文档文本中任何位置是否存在关键字,一个可行的解决方法是将 XML 转换为文本,然后使用上述方法之一。这是一个例子:
#pip install libxml2-python3 trieregex
from trieregex import TrieRegEx as TRE
from libxml2 import parseDoc
import re
# prepare
words = ['lemon', 'lemons', 'lime', 'limes', 'pomelo', 'pomelos', 'orange', 'oranges', 'citrus', 'citruses']
tre = TRE(*words)
pattern = re.compile(fr"\b{tre.regex()}\b")
# => \b(?:l(?:emons?|imes?)|citrus(?:es)?|oranges?|pomelos?)\b
# search
xml = """
<?xml version="1.0"?>
<recipe>
<substitute for="lemon">three limes</substitute>
<substitute for="orange">pomelo</substitute>
</recipe>
""".strip()
doc = parseDoc(xml)
text = doc.getContent()
matches = pattern.findall(text)
print(matches)
# => ['limes', 'pomelo']
doc.freeDoc()
请注意,您只需要准备一次正则表达式;然后您可以在多个文档上快速应用它。