jjzjj

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

coder 2024-06-23 原文

重新审视一个停滞不前的项目,并寻求对数千个“旧”文档进行现代化改造并通过网络提供它们的建议。

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

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

好奇其他人会如何处理这个问题。没有“错误”的答案,我只是在寻找尽可能多的输入来帮助我们继续。

感谢您的任何建议。

最佳答案

总结:我要推荐 ElasticSearch ,但是让我们把问题分解一下,谈谈如何实现它:

这有几个部分:

  • 从您的文档中提取文本以使其可索引
  • 使此文本可用作全文搜索
  • 返回文档的突出显示片段
  • 知道在文档中的何处找到这些片段以允许
    用于寻呼
  • 返回完整文档

  • ElasticSearch 可以提供什么:
  • ElasticSearch(如 Solr)使用 Tika从各种文档中提取文本和元数据 formats
  • 很明显,它提供了强大的全文搜索。可以配置
    以适当的语言分析每个文档,并增加某些领域的相关性(例如,标题比内容更重要)、ngram 等,即标准的 Lucene 内容
  • 可以返回highlighted snippets对于每个搜索结果
  • 它不知道这些片段出现在您的文档中的何处
  • 它可以将原始文档存储为 attachment ,或者它可以存储和返回提取的文本。但它会返回整个文档,而不是页面。

  • 您可以将整个文档作为附件发送到 ElasticSearch,您将获得全文搜索。但症结在于上面的 (4) 和 (5):知道您在文档中的位置,并返回文档的一部分。

    存储单个页面可能足以满足您的 where-am-I 目的(尽管您同样可以下到段落级别),但您希望它们以一种将在搜索结果中返回文档的方式分组,即使出现搜索关键字在不同的页面上。

    首先是索引部分:将您的文档存储在 ElasticSearch 中:
  • 使用 Tika(或您喜欢的任何工具)从每个文档中提取文本。将其保留为纯文本或 HTML 以保留某些格式。 (忘记 XML,不需要它)。
  • 还提取每个文档的元数据:标题、作者、章节、语言、日期等
  • 将原始文档存储在您的文件系统中,并记录路径以便您稍后提供它
  • 在 ElasticSearch 中,索引一个包含所有元数据的“doc”文档,可能还有章节列表
  • 将每个页面索引为“页面”文档,其中包含:
  • parent field其中包含“doc”文档的 ID(参见下面的“父子关系”)
  • 正文
  • 页码
  • 也许是章节标题或编号
  • 您希望可搜索的任何元数据

  • 现在进行搜索。您如何执行此操作取决于您希望如何呈现结果 - 按页面或按文档分组。

    按页显示结果很容易。此查询返回匹配页面的列表(每个页面都完整返回)以及页面中突出显示的片段列表:
    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查找其子项(“页面”)与查询最匹配的父项(“文档”):
    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 步:从上述查询中收集“文档”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 步:在您的应用中,将上述查询的结果按 doc 分组并显示出来。

    通过第二个查询的搜索结果,您已经拥有了可以显示的页面全文。要移动到下一页,您只需搜索它:
    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 解决方案)中,每个文档/对象都是独立的——没有真正的关系。通过在“文档”和“页面”之间建立父子关系,ElasticSearch 确保子文档(即“页面”)与父文档(“文档”)存储在同一个分片上。

    这使您能够运行 top-children-query它将根据“页面”的内容找到最匹配的“文档”。

    关于xml - 数千个文档(pdf 和/或 xml)的可搜索存档的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10854858/

    有关xml - 数千个文档(pdf 和/或 xml)的可搜索存档的最佳实践的更多相关文章

    1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

      很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

    2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

      我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

    3. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

      我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

    4. ruby-on-rails - Nokogiri:使用 XPath 搜索 <div> - 2

      我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll

    5. ruby-on-rails - Prawn PDF : I need to generate nested tables - 2

      我需要一个表,其中行实际上是2行表,一个嵌套表是..我怎样才能在Prawn中做到这一点?也许我需要延期..但哪一个? 最佳答案 现在支持子表:Prawn::Document.generate("subtable.pdf")do|pdf|subtable=pdf.make_table([["sub"],["table"]])pdf.table([[subtable,"original"]])end 关于ruby-on-rails-PrawnPDF:Ineedtogeneratenested

    6. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

      导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

    7. Matlab imread()读到了什么 (浅显 当复习文档了) - 2

      matlab打开matlab,用最简单的imread方法读取一个图像clcclearimg_h=imread('hua.jpg');返回一个数组(矩阵),往往是a*b*cunit8类型解释一下这个三维数组的意思,行数、数和层数,unit8:指数据类型,无符号八位整形,可理解为0~2^8的数三个层数分别代表RGB三个通道图像rgb最常用的是24-位实现方法,即RGB每个通道有256色阶(2^8)。基于这样的24-位RGB模型的色彩空间可以表现256×256×256≈1670万色当imshow传入了一个二维数组,它将以灰度方式绘制;可以把图像拆分为rgb三层,可以以灰度的方式观察它figure(1

    8. ruby-on-rails - Rails 中同一个类的多个关联的最佳实践? - 2

      我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来

    9. ruby - 如何搜索有用的 ruby - 2

      寻找有用的ruby的好网站是什么? 最佳答案 AgileWebDevelopment列出插件(虽然不是ruby​​gems,我不确定为什么),并允许人们对它们进行评级。RubyToolbox按类别列出gem并比较它们的受欢迎程度。Rubygems有一个搜索框。StackOverflow对最有用的rails插件和ruby​​gems有疑问。 关于ruby-如何搜索有用的ruby,我们在StackOverflow上找到一个类似的问题: https://stacko

    10. ruby-on-rails - 向 Rails 3 添加 Ruby 扩展方法的最佳实践? - 2

      我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion

    随机推荐