web-dev-qa-db-fra.com

Meilleures pratiques pour l'archivage consultable de milliers de documents (pdf et / ou xml)

Revisiter un projet au point mort et rechercher des conseils pour moderniser des milliers de "vieux" documents et les rendre disponibles via le web.

Les documents existent dans différents formats, certains obsolètes: (. Doc, PageMaker, copie papier (OCR), PDF , etc.). Des fonds sont disponibles pour migrer les documents dans un format "moderne", et bon nombre des copies papier ont déjà été OCR en PDF - nous avions initialement supposé que PDF serait le format final mais nous suis ouvert aux suggestions (XML?).

Une fois que tous les documents sont dans un format commun, nous aimerions rendre leur contenu disponible et consultable via une interface Web. Nous aimerions avoir la possibilité de renvoyer uniquement des parties (pages?) Du document entier où une recherche a été trouvée (je crois que Lucene/elasticsearch rend cela possible?!?) Cela pourrait-il être plus flexible si le contenu était entièrement XML? Si oui, comment/où stocker le XML? Directement dans la base de données ou sous forme de fichiers discrets dans le système de fichiers? Qu'en est-il des images/graphiques intégrés dans les documents?

Curieux de voir comment les autres pourraient aborder cela. Il n'y a pas de "mauvaise" réponse. Je cherche juste autant d'entrées que possible pour nous aider à continuer.

Merci pour tout conseil.

44
Meltemi

En résumé: je vais recommander ElasticSearch , mais décomposons le problème et parlons de la façon de l'implémenter:

Il y a quelques parties à cela:

  1. Extraire le texte de vos documents pour les rendre indexables
  2. Rendre ce texte disponible en recherche plein texte
  3. Retour d'extraits en surbrillance du document
  4. Savoir où dans le document ces extraits sont trouvés pour permettre la pagination
  5. Retournez le document complet

Que peut fournir ElasticSearch:

  1. ElasticSearch (comme Solr) utilise Tika pour extraire du texte et des métadonnées à partir d'une grande variété de documents formats
  2. De toute évidence, il fournit une puissante recherche en texte intégral. Il peut être configuré pour analyser chaque document dans la langue appropriée avec, en développant, en renforçant la pertinence de certains champs (par exemple, le titre est plus important que le contenu), les ngrammes, etc.
  3. Il peut retourner extraits en surbrillance pour chaque résultat de recherche
  4. Il NE SAIT PAS où ces extraits se produisent dans votre doc
  5. Il peut stocker le document d'origine en tant que pièce jointe , ou il peut stocker et renvoyer le texte extrait. Mais cela retournera le document entier, pas une page.

Vous pouvez simplement envoyer le document entier à ElasticSearch sous forme de pièce jointe, et vous obtiendrez une recherche en texte intégral. Mais les points d'achoppement sont (4) et (5) ci-dessus: savoir où vous êtes dans un document et renvoyer des parties d'un document.

Le stockage de pages individuelles est probablement suffisant pour vos besoins où-suis-je (bien que vous puissiez également descendre au niveau du paragraphe), mais vous souhaitez les regrouper de manière à ce qu'un document soit renvoyé dans les résultats de la recherche, même si des mots clés de recherche apparaissent sur différentes pages.

Tout d'abord la partie indexation: stocker vos documents dans ElasticSearch:

  1. Utilisez Tika (ou ce que vous êtes à l'aise) pour extraire le texte de chaque document. Laissez-le en texte brut ou en HTML pour conserver une mise en forme. (oubliez XML, pas besoin).
  2. Extrayez également les métadonnées de chaque document: titre, auteurs, chapitres, langue, dates, etc.
  3. Stockez le document d'origine dans votre système de fichiers et enregistrez le chemin afin de pouvoir le servir plus tard
  4. Dans ElasticSearch, indexez un document "doc" qui contient toutes les métadonnées, et éventuellement la liste des chapitres
  5. Indexez chaque page en tant que document "page", qui contient:

    • A champ parent qui contient l'ID du doc ​​"doc" (voir "Relation parent-enfant" ci-dessous)
    • Le texte
    • Le numéro de page
    • Peut-être le titre ou le numéro du chapitre
    • Toutes les métadonnées que vous souhaitez rechercher

Maintenant pour chercher. La façon dont vous procédez dépend de la façon dont vous souhaitez présenter vos résultats - par page ou groupés par doc.

Les résultats par page sont faciles. Cette requête renvoie une liste de pages correspondantes (chaque page est renvoyée dans son intégralité) plus une liste d'extraits de code en surbrillance de la page:

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

L'affichage des résultats regroupés par "doc" avec les reflets du texte est un peu plus délicat. Cela ne peut pas être fait avec une seule requête, mais un petit regroupement côté client vous y mènera. Une approche pourrait être:

Étape 1: effectuez une top-children-query pour trouver le parent ("doc") dont les enfants ("page") correspondent le mieux à la requête:

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"
      }
   }
}

Étape 2: collectez les ID "doc" de la requête ci-dessus et émettez une nouvelle requête pour obtenir les extraits des documents "page" correspondants:

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" : {}
      }
   }
}
'

Étape 3: dans votre application, regroupez les résultats de la requête ci-dessus par doc et affichez-les.

Avec les résultats de recherche de la deuxième requête, vous disposez déjà du texte intégral de la page que vous pouvez afficher. Pour passer à la page suivante, vous pouvez simplement la rechercher:

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
}
'

Ou bien, attribuez aux documents "page" un ID composé de $doc_id _ $page_num (par exemple 123_2), vous pouvez simplement récupérer cette page:

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

Relation parent-enfant:

Normalement, dans ES (et la plupart des solutions NoSQL), chaque document/objet est indépendant - il n'y a pas de vraies relations. En établissant une relation parent-enfant entre le "doc" et la "page", ElasticSearch s'assure que les documents enfants (c'est-à-dire la "page") sont stockés sur le même fragment que le doc parent (le "doc").

Cela vous permet d'exécuter la top-children-query qui trouvera le "doc" correspondant le mieux en fonction du contenu des "pages".

114
DrTech

J'ai construit et maintenu une application qui indexe et recherche 70k + PDF. J'ai trouvé que c'était nécessairement pour extraire le texte brut des PDF, stocker le contenu en SQL et indexer la table SQL en utilisant Lucene. Sinon, les performances étaient horribles.

2
Josh Siok

Utilisez Sunspot ou RSolr ou similaire, il gère la plupart des principaux formats de document. Ils utilisent Solr/Lucene.

2
Dave Newton