【问题标题】:How to speed up search for a line containing needed text?如何加快搜索包含所需文本的行?
【发布时间】:2020-01-16 04:36:31
【问题描述】:

我有第一个文件(大小约为 1-3 kb),其中几行如下所示::

Name1
Name2
Name3
Name4
etc

还有第二个文件(大小为 1.2 GB),其中的字符串如下所示:

<root><img>url</img><title>Name1</title>(a few more tags there)</root>

第二个文件包含第一个文件的所有名称(以及与 file1 相同的文件的名称),但包含附加信息。

我需要一个代码来遍历 file1 的每一行,从那里获取名称并在文件 2 中查找包含相同名称的标记。找到包含所需名称的标记后,需要复制父级根标签及其中的所有内容输出文件。

我得到了这个代码:

root = ET.parse('file2.xml').getroot()

with open('output.xml', 'a') as x, open('file1.xml', 'r') as f:
    for line in f:
        element = line
        search = root.xpath('.//root/Title[text()="%s"]' % element)
        for i in search:
            print(ET.tostring(i.getparent().decode('utf-8')))

它可以工作,但速度很慢,我需要加快这段代码的速度

问题:我怎样才能加快这段代码的速度,或者是否有另一种快速的方法来逐文本搜索元素?

编辑

大文件中每一行的结构(印刷精美)

<root>
  <Big_Images>
    <Big_Images0>url to img</Big_Images0>
    <Big_Images1>url to img</Big_Images1>
  </Big_Images>
  <Small_Images>
    <Small_Images0>url to small img</Small_Images0> 
    <Small_Images1>url to small img</Small_Images1> 
  </Small_Images>
  <title>Name1</title>
  <Summary/> # can contain some info
  <Price>4.1</Price>
  <Main_Info>
    <item>many html code there</item>
  </Main_Info>
</root>

Small_Images(number from 0(&lt;Small_Images/&gt;) to 10) 总是等于 Big_Images(number from 0(&lt;Big_Images/&gt;) to 10)

我还删除了所有重复的字符串(在一个大文件中)。要么没有包含例如 Name1 的字符串,要么只有 1 个包含 Name1 的字符串。

root 总是包含 1 个title 标签

只有 SummaryBig_ImagesSmall_Images 可能没有元素

在xml文件中有1个父标签data,每一行都有一个root

【问题讨论】:

  • Idea1: .//root/title 可能效率低下。请改用/root/title(这假设&lt;root&gt; 确实是您的XML 文件的根标记。如果不是,请适当调整)。想法2:不是顺序读取小文件,随机搜索大文件,而是先将小文件读入内存(例如读入一个集合),然后依次读入大文件,然后在内存中查找集合中的名称。
  • 就 XPath 而言,显式选择root/Title 然后使用i.getparent 似乎有点奇怪,似乎直接使用search = root.xpath('.//root[title ="%s"]' % element) 然后简单地使用print(ET.tostring(i.decode('utf-8'))) 就足够了。我没有进行任何测试是否可以提高性能。一般来说,对于这么大的数据(1.2 GB),使用像 BaseX 这样的数据库可能是有意义的,因为它允许您构建索引,然后搜索变得更快。 BaseX 是用 Java 实现的,但有一个 Python 客户端 API docs.basex.org/wiki/Clients
  • 如果您提供有关确切文件结构的更多详细信息会有所帮助,特别是是否存在或是否存在具有相同值的多个 title 元素(例如,多个 &lt;title&gt;Name1&lt;/title&gt; 元素)? title 元素的父元素是否总是 root 元素?这些title 元素的嵌套级别是始终相同还是不同级别?
  • 我更新了表头的数据。

标签: python regex xml lxml


【解决方案1】:

感谢大家的建议,就我而言,我编写了以下工作代码:

with open('main_data_file.xml', 'r') as f:
    txt = ''.join(f.readlines())
    with open('names.txt', 'r') as g, open('output.txt', 'a') as x:
        for element in g.readlines():
            line_regexp = r'^(.*<title>%s</title>.*)$' % element
            matches = re.search(line_regexp, txt, re.MULTILINE)
            try:
              x.write(matches + "\n")
            except AttributeError:
              pass

但他还是太慢了(1 KB 大约需要 5 秒)

我不知道我错在哪里,我可以更快地搜索到具有正确名称的行吗?

编辑

我已经测试了很多,找到了适合我的代码:

data_set = set()
with open('main_data_file.xml', 'r') as f:
    data_set.update(f.readlines())
    with open("names.txt", 'r', encoding='utf-8') as g, open("output.txt", 'a') as x:
        for line in g.readlines():
            line_regexp = '<title>%s</title>' % line.strip()
            # print('Searching line:' + line_regexp)
            for element in data_set:
                if line_regexp in element:
                    x.write(element)
                    # print('Element found ' + line.strip() + "\n")

以足够高的速度运行

【讨论】:

  • 据我了解,问题是re.search(),你怎么看?
【解决方案2】:

也许你可以尝试正则表达式方法

import re

names = []
with open("small_file", "r") as f:
    names = f.readlines()

with open("big_file", "r") as f:
    pattern = re.compile(r"\<root\>[\W\w]*\<\/root\>")
    lines = f.readlines()
    for line in lines:
        match = pattern.search(line)
        if match:
            print(line)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-07
    • 2014-05-24
    • 2013-10-27
    • 1970-01-01
    • 2010-09-19
    • 1970-01-01
    相关资源
    最近更新 更多