web-dev-qa-db-fra.com

Comment rechercher rapidement dans une très grande liste de chaînes / enregistrements dans une base de données

J'ai le problème suivant: J'ai une base de données contenant plus de 2 millions d'enregistrements. Chaque enregistrement a un champ de chaîne X et je souhaite afficher une liste des enregistrements pour lesquels le champ X contient une certaine chaîne. Chaque enregistrement a une taille d'environ 500 octets.

Pour le rendre plus concret: dans l'interface graphique de mon application, j'ai un champ de texte où je peux entrer une chaîne. Au-dessus du champ de texte, j'ai un tableau affichant les (premiers N, par exemple 100) enregistrements qui correspondent à la chaîne dans le champ de texte. Lorsque je tape ou supprime un caractère dans le champ de texte, le contenu du tableau doit être mis à jour à la volée.

Je me demande s'il existe un moyen efficace de le faire en utilisant des structures d'index appropriées et/ou la mise en cache. Comme expliqué ci-dessus, je souhaite uniquement afficher les N premiers éléments correspondant à la requête. Par conséquent, pour N suffisamment petit, cela ne devrait pas être un gros problème de chargement des éléments correspondants à partir de la base de données. De plus, la mise en cache des éléments dans la mémoire principale peut accélérer la récupération.

Je pense que le principal problème est de trouver rapidement les éléments correspondants, compte tenu de la chaîne de modèle. Puis-je compter sur certaines fonctionnalités du SGBD ou dois-je créer moi-même un index en mémoire? Des idées?

MODIFIER

J'ai exécuté une première expérience. J'ai divisé les enregistrements en différents fichiers texte (au plus 200 enregistrements par fichier) et placé les fichiers dans différents répertoires (j'ai utilisé le contenu d'un champ de données pour déterminer l'arborescence des répertoires). Je me retrouve avec environ 50000 fichiers dans environ 40000 répertoires. J'ai ensuite exécuté Lucene pour indexer les fichiers. La recherche d'une chaîne avec le programme de démonstration Lucene est assez rapide. Le fractionnement et l'indexation ont pris quelques minutes: c'est tout à fait acceptable pour moi car c'est un ensemble de données statiques que je souhaite interroger.

L'étape suivante consiste à intégrer Lucene dans le programme principal et à utiliser les hits renvoyés par Lucene pour charger les enregistrements pertinents dans la mémoire principale.

33
Giorgio

Au lieu de mettre vos données à l'intérieur de la base de données, vous pouvez les conserver sous forme d'un ensemble de documents (fichiers texte) séparément et conserver le lien (chemin/URL, etc.) dans la base de données.

Ceci est essentiel car, par conception, la requête SQL sera très lente à la fois dans la recherche de sous-chaîne et dans la récupération.

Maintenant, votre problème est formulé comme: avoir à rechercher les fichiers texte qui contiennent l'ensemble de chaînes. Il y a deux possibilités ici.

  1. Correspondance de sous-chaîne Si vos taches de texte sont une seule piqûre ou un mot (sans espace blanc) et que vous devez rechercher une sous-chaîne arbitraire à l'intérieur. Dans de tels cas, vous devez analyser chaque fichier pour trouver les meilleurs fichiers possibles qui correspondent. On utilise des algorithmes comme l'algorithme de Boyer Moor. Voir this et this pour plus de détails. Ceci est également équivalent à grep - car grep utilise des éléments similaires à l'intérieur. Mais vous pouvez toujours faire au moins 100+ grep (pire cas 2 millions) avant de revenir.

  2. Recherche indexée. Ici, vous supposez que le texte contient un ensemble de mots et que la recherche est limitée à des longueurs de mot fixes. Dans ce cas, le document est indexé sur toutes les occurrences possibles de mots. Ceci est souvent appelé "recherche de texte intégral". Il existe un certain nombre d'algorithmes pour ce faire et un certain nombre de projets open source qui peuvent être utilisés directement. Beaucoup d'entre eux prennent également en charge la recherche générique, la recherche approximative, etc. comme ci-dessous:
    une. Apache Lucene: http://lucene.Apache.org/Java/docs/index.html
    b. OpenFTS: http://openfts.sourceforge.net/
    c. Sphinx http://sphinxsearch.com/

Très probablement, si vous avez besoin de "mots fixes" comme requêtes, l'approche deux sera très rapide et efficace.

20
Dipan Mehta

La technologie que vous recherchez est l'indexation de texte intégral. La plupart des SGBDR ont une sorte de capacités intégrées qui pourraient fonctionner ici, ou vous pouvez utiliser quelque chose comme Lucene si vous voulez devenir plus sophistiqué et/ou simplement l'exécuter en mémoire.

21
Wyatt Barnett

Avez-vous pensé à un trie ? Fondamentalement, vous construisez un arbre en utilisant des préfixes communs, donc tous les mots qui commencent par les mêmes lettres sont des enfants du même nœud. Si vous allez prendre en charge la correspondance sur n'importe quelle sous-chaîne, vous devrez générer une sorte de index permuté et construire votre trie à partir de cela. Cela peut finir par faire exploser vos besoins de stockage.

8
TMN

Je voudrais ajouter en plus de la réponse de Wyatt Barnett qu'une solution SGBDR avec indexation en texte intégral sur la colonne appropriée fonctionnera, mais si vous souhaitez utiliser un cache local d'enregistrements précédemment récupérés, vous devez planifier pour utiliser ces enregistrements en cache à votre avantage.

Une option consiste à collecter les identifiants uniques de ces enregistrements que vous ne souhaitez EXPLICITEMENT pas extraire de la requête et les inclure, éventuellement dans un NOT IN ou un NOT EXISTS.

Attention cependant, en utilisant NOT IN ou NOT EXISTS a tendance à ne pas être bon marché et PEUT influencer négativement les performances ou le plan de requête en fonction du moteur de base de données que vous utilisez. Exécutez un plan d'explication sur votre requête finale pour vous assurer que tous vos index sur les colonnes affectées sont utilisés.

Cela ne fait pas de mal non plus de faire une comparaison des performances entre les deux approches pour voir laquelle est la plus rapide. Vous serez peut-être surpris de découvrir que le maintien d'un cache local et le filtrage explicite de ceux de votre requête peuvent avoir de moins bonnes performances qu'une requête finement réglée qui récupère tous les enregistrements.

5
maple_shaft

Juste au cas où vous l'auriez manqué. Si vous utilisez Lucene pour votre base de données au lieu de la recherche de texte prise en charge dans la base de données, vous devrez être extrêmement prudent lors de la modification de votre base de données. Comment vous assurez-vous que vous pouvez avoir l'atomicité lorsque vous devez apporter des modifications à la fois à la base de données et aux ressources externes (Lucene)? Oui, cela peut être fait, mais il y aura beaucoup de travail.

En bref, vous perdez le support transactionnel DB si vous mettez Lucene dans votre schéma de données.

2
InformedA

Il est quelque peu étrange qu'aucune des réponses ne présente le terme "index inversé" , la technologie sous-jacente à toutes les solutions similaires à Apache Lucene et à d'autres.

L'index inversé est un mappage des mots vers les documents ("index inversé au niveau de l'enregistrement") ou même des emplacements précis de Word dans le document ("index inversé au niveau du mot").

ET et OR les opérations logiques sont triviales à implémenter. Si vous avez des emplacements précis de Word, il est possible de rechercher des mots adjacents, ce qui permet des recherches de phrases.

Pensez donc à un index contenant (Word, fichier, emplacement) des tuples. Lorsque vous avez par exemple ("inversé", "foo.txt", 123), il vous suffit de vérifier si ("index", "foo.txt", 124) fait partie de l'index pour rechercher la phrase complète "index inversé".

Bien que je ne vous recommande pas de réimplémenter un moteur de recherche de texte intégral à partir de zéro, il est utile de savoir comment fonctionnent des technologies telles qu'Apache Lucene.

Donc, ma recommandation est d'apprendre comment fonctionnent les index inversés et de choisir une technologie qui les utilise comme Apache Lucene. Ensuite, vous avez au moins une solide compréhension de ce qui peut être fait et de ce qui ne peut pas être fait.

1
juhist

Avez-vous pensé au Sphinx? http://sphinxsearch.com si vous pouvez utiliser un outil tiers, ce serait idéal pour ce que vous essayez de réaliser, c'est beaucoup plus efficace pour la recherche en texte intégral que n'importe quel SGBDR que j'ai personnellement utilisé.

1
twigg