可搜索的数千个文档存档的最佳实践(pdf和/或xml)

时间:2012-06-01 17:32:07

标签: xml pdf lucene full-text-search elasticsearch

重新审视一个停滞不前的项目,并寻求有关现代化数千个“旧”文档并通过网络提供这些文档的建议。

文档以各种格式存在,有些已过时:( .doc PageMaker ,硬拷贝(OCR), PDF 等)。资金可用于将文档迁移到“现代”格式,并且许多硬拷贝已经被OCR转换为PDF格式 - 我们原先假设PDF将是最终格式,但我们愿意接受建议(XML?) 。

一旦所有文档都采用通用格式,我们就希望其内容可用,并且可通过网络界面搜索。我们希望能够灵活地返回整个文档中找到搜索“命中”的部分(页面?)(我相信Lucene / elasticsearch使这成为可能吗?!?)如果内容全部是XML,那么它可能更灵活吗?如果是这样,如何/在哪里存储XML?直接在数据库中,还是作为文件系统中的离散文件?如何在文档中嵌入图像/图形?

好奇其他人如何接近这一点。没有“错误”的答案我只是在寻找尽可能多的输入来帮助我们继续前进。

感谢您的任何建议。

3 个答案:

答案 0 :(得分:112)

总结:我将推荐ElasticSearch,但让我们解决问题,并讨论如何实施它:

这有几个部分:

  1. 从文档中提取文本以使其可转换为
  2. 将此文本作为全文搜索提供
  3. 返回文档
  4. 的突出显示片段
  5. 知道文档中的哪些片段被发现允许 用于传呼
  6. 返回完整文档
  7. ElasticSearch可以提供什么:

    1. ElasticSearch(与Solr一样)使用Tika从各种文档中提取文本和元数据formats
    2. 很明显,它提供了强大的全文搜索功能。它可以配置 用适当的语言分析每个文档,阻止,提高某些领域的相关性(例如标题比内容更重要),ngrams等,即标准的Lucene东西
    3. 每个搜索结果都可以返回highlighted snippets
    4. 它不知道你的文档中出现了哪些片段
    5. 它可以将原始文档存储为attachment,也可以存储和返回提取的文本。但它会返回整个文档,而不是页面。
    6. 您可以将整个文档作为附件发送到ElasticSearch,然后您将获得全文搜索。但关键点在于上面的(4)和(5):知道你在文档中的位置,以及返回文档的部分内容。

      存储单个页面可能足以满足您的“我在哪里”的目的(尽管您可以同样地进入段落级别),但是您希望它们按照在搜索结果中返回文档的方式进行分组,即使搜索关键字出现在不同的网页上。

      首先是索引部分:将您的文档存储在ElasticSearch中:

      1. 使用Tika(或您喜欢的任何内容)从每个文档中提取文本。将其保留为纯文本或HTML,以保留一些格式。 (忘记XML,不需要它)。
      2. 还提取每个文档的元数据:标题,作者,章节,语言,日期等
      3. 将原始文档存储在文件系统中,并记录路径以便以后提供
      4. 在ElasticSearch中,索引一个“doc”文档,其中包含所有元数据,可能还包含章节列表
      5. 将每个页面编入“页面”文档,其中包含:

        • 一个parent field,其中包含“doc”文档的ID(请参阅下面的“亲子关系”)
        • 文字
        • 页码
        • 可能是章节标题或编号
        • 您想要搜索的任何元数据
      6. 现在进行搜索。如何执行此操作取决于您希望如何按页面显示结果,或按文档分组。

        页面结果很简单。此查询返回匹配页面的列表(每个页面完整返回)以及页面中突出显示的片段列表:

        curl -XGET 'http://127.0.0.1:9200/my_index/page/_search?pretty=1'  -d '
        {
           "query" : {
              "text" : {
                 "text" : "interesting keywords"
              }
           },
           "highlight" : {
              "fields" : {
                 "text" : {}
              }
           }
        }
        '
        

        显示按“doc”分组的结果以及文本中的突出显示有点棘手。它不能通过单个查询完成,但是一个小客户端分组将帮助您。一种方法可能是:

        步骤1:执行top-children-query查找其子级(“页面”)与查询最匹配的父级(“doc”):

        curl -XGET 'http://127.0.0.1:9200/my_index/doc/_search?pretty=1'  -d '
        {
           "query" : {
              "top_children" : {
                 "query" : {
                    "text" : {
                       "text" : "interesting keywords"
                    }
                 },
                 "score" : "sum",
                 "type" : "page",
                 "factor" : "5"
              }
           }
        }
        

        第2步:收集上述查询中的“doc”ID并发出新查询以从匹配的“页面”文档中获取摘要:

        curl -XGET 'http://127.0.0.1:9200/my_index/page/_search?pretty=1'  -d '
        {
           "query" : {
              "filtered" : {
                 "query" : {
                    "text" : {
                       "text" : "interesting keywords"
                    }
                 },
                 "filter" : {
                    "terms" : {
                       "doc_id" : [ 1,2,3],
                    }
                 }
              }
           },
           "highlight" : {
              "fields" : {
                 "text" : {}
              }
           }
        }
        '
        

        第3步:在您的应用中,按文档对上述查询的结果进行分组并显示它们。

        使用第二个查询的搜索结果,您已经拥有了可以显示的页面的全文。要移至下一页,您只需搜索它:

        curl -XGET 'http://127.0.0.1:9200/my_index/page/_search?pretty=1'  -d '
        {
           "query" : {
              "constant_score" : {
                 "filter" : {
                    "and" : [
                       {
                          "term" : {
                             "doc_id" : 1
                          }
                       },
                       {
                          "term" : {
                             "page" : 2
                          }
                       }
                    ]
                 }
              }
           },
           "size" : 1
        }
        '
        

        或者,为“页面”文档提供一个由$doc_id _ $page_num组成的ID(例如123_2),然后您就可以检索该页面:

        curl -XGET 'http://127.0.0.1:9200/my_index/page/123_2
        

        亲子关系:

        通常,在ES(和大多数NoSQL解决方案)中,每个doc / object都是独立的 - 没有真正的关系。通过在“doc”和“page”之间建立父子关系,ElasticSearch确保子文档(即“页面”)与父文档(“doc”)存储在同一个分片上。

        这使您可以运行top-children-query,根据“网页”的内容找到最匹配的“doc”。

答案 1 :(得分:2)

我已经构建并维护了一个索引和搜索70k + PDF文档的应用程序。我发现必须从PDF中提取纯文本,将内容存储在SQL中并使用Lucene索引SQL表。否则,表现太可怕了。

答案 2 :(得分:2)

使用SunspotRSolr或类似内容,它可处理大多数主要文档格式。他们使用Solr / Lucene。