在多个XML文件中搜索字符串

3
我有一个包含400k+个XML文档的文件夹,还有更多的文件将会到来,每个文件都以'ID'.xml命名,并且每个文件都属于特定的用户。在SQL服务器数据库中,我将XML文件的'ID'与userID匹配,这就是我将XML文档与用户相互关联的地方。一个用户可以拥有无限数量的XML文档(但假设最多> 10k个文档)。
所有的XML文档都有一些共同的元素,但结构可能会有所不同。
现在,每个用户都需要对属于她的XML文档进行搜索,而我尝试过的方法(循环遍历每个文件并使用streamreader读取它)速度太慢了。我不介意它是否阅读并匹配整个文件及其属性等内容,或者只是每个元素中的文本。首先应返回一个包含文件名中ID的列表。
如果有的话,最快、最聪明的方法是什么?

将Xml文件解析一次,然后使用Lucene.Net对它们进行索引。 - L.B
7个回答

2
您需要打开包含相关数据的每个文件,如果您不知道哪些文件包含它,您需要打开所有可能匹配的文件。因此,唯一的性能提升将在解析例程中体现。
当解析Xml时,如果速度是要求,您可以使用XmlReader,因为它比其他解析器执行得更好(大多数解析器在您查询它们之前读取整个Xml文件)。它只能向前读取的事实对于这种情况不应该是限制。
如果解析时间与磁盘I/O时间大致相同,则可以尝试并行解析文件,因此一个线程可以等待读取文件,而另一个线程解析加载的数据。虽然我认为您无法在那里获得太大的胜利。
还有什么是“太慢”的,什么是可以接受的?这种许多文件的解决方案会随着时间的推移变得更加缓慢吗?

2

我认为LINQ-to-XML可能是您想要的方向。

假设您知道您想要的标记名称,您可以搜索这些特定元素并返回其值。

var xDoc = XDocument.Load("yourFile.xml");

var result = from dec in xDoc.Descendants()
             where dec.Name == "tagName"
             select dec.Value;

results 将包含一个 IEnumerable,其中包含任何名称匹配 "tagName" 的 XML 标记的值。

查询也可以这样写:

var result = from dec in xDoc.Decendants("tagName")
             select dec.Value;

或者这个:
var result = xDoc.Descendants("tagName").Select(tag => tag.Value);

输出结果一样,只是基于元素名称进行过滤的另一种不同方法。

做了类似这样的事情,目前在搜索时是可以接受的:IEnumerable<XName> result = xDoc.Descendants("Root").Where(dec => dec.Value.ToLower().Contains(TextBox1.Text.ToLower())).Select(dec => dec.Name); - Thomas

1

使用 LINQ to XML。

请查看 msdn 上的 this 文章。

XDocument doc = XDocument.Load("C:\file.xml");

不要忘记,读取这么多文件总是会很慢,你可以尝试编写一个多线程程序...


1
如果我理解正确,您不想为特定用户打开每个xml文件,因为无论您使用linq to xml还是其他方法,这都太慢了。您考虑过在xml文件和关系数据库(标签)中保存一些值(连同xml ID)吗?在这种情况下,您可以首先在DB中搜索某些值,然后仅选择包含搜索值的xml文件。
例如: ID,tagName1,tagName2 xmlDocID,value1,value2
我的另一个问题是,为什么选择将xml文档存储在文件系统中。如果您正在使用SQL Server 2005/2008,则它对存储、搜索xml列(甚至索引xml中的某些值)具有非常好的支持。

我还没有考虑过这个,但我会看看 Linq to XML 是否比我的 streamreaders 更好 - 希望如此。关于你的问题,这些 XML 文档每晚从不同的来源批量上传 - 通过 ftp 等方式,并且它们有一个选项可以在短时间内进行编辑... - Thomas
好的,如果 Linq to XML 仍然表现缓慢,你可以进行某种类型的 XML 后处理(在上传 XML 后)并将一些感兴趣的值存储在数据库中。 - Milan Svitlica
如果您能够确定XML中用于搜索的内容,那么采用这种方法会得到+1。 - EdSF

0

您是否只是在查找内容中具有特定字符串的文件某个地方

警告-不是纯的.NET解决方案。如果这让您感到害怕,请坚持其他答案。 :)

如果您正在这样做,另一种选择是获取类似grep这样的东西来为您处理繁重的工作。使用"-l"参数将其外壳化,以指定您仅对文件名感兴趣,那么您就是赢家了。 (有关更多用法示例,请参见this link


最好只在文本区域中找到内容,而不是在属性、名称等中找到...不过我会看一下,看哪个表现得最好。尽管这让我有些害怕;-) - Thomas

0

L.B已经提出了一个有效的观点。 这是一个情况,其中Lucene.Net(或任何索引器)将是必须的。它将为您提供稳定(非常快速)的性能,在所有搜索中都是如此。这是索引器的主要优势之一,可以处理大量任意数据。

或者,您有任何理由不使用Lucene吗?


其实我不知道Lucene.Net。但是我每天都会收到新的XML文件,这对索引是否有影响呢?虽然我从未涉及过索引,但如果有很多好处,也许我应该去了解一下? - Thomas
不用每次都重新索引整个结构 - 只需在编写新的 XML 文件的子文件夹中启动索引器即可。但是如果需要,您可以安排它每天运行完整的重新索引2次或其他时间。无论如何,索引器所做的工作并不比必须要做的多。因此,您可以使用索引器。 - Sandbeck

0
Lucene.NET(以及Lucene)支持增量索引。如果您可以定期重新打开索引以进行读取,则可以整天向索引中添加文档 - 您的搜索将与您上次重新打开索引以进行搜索的时间保持最新状态。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接