Accélérer la regex de la chaîne de recherche dans MongoDB
Je suis en train d'utiliser MongoDB pour mettre en œuvre un naturel dictionnaire de la langue. J'ai une collection de lexèmes, dont chacune a un certain nombre de wordforms comme sous-documents. C'est ce qu'un seul lexeme ressemble:
{
"_id" : ObjectId("51ecff7ee36f2317c9000000"),
"pos" : "N",
"lemma" : "skrun",
"gloss" : "screw",
"wordforms" : [
{
"number" : "sg",
"surface_form" : "skrun",
"phonetic" : "ˈskruːn",
"gender" : "m"
},
{
"number" : "pl",
"surface_form" : "skrejjen",
"phonetic" : "'skrɛjjɛn",
"pattern" : "CCCVCCVC"
}
],
"source" : "Mayer2013"
}
Actuellement, j'ai une collection de plus de 4000 lexèmes, et chacun d'eux a en moyenne une liste de quelques 1000 wordforms (par opposition à seulement 2 ci-dessus). Cela signifie que je affectivement avons 4 000 000 de unique de formes de mots dans la collection, et j'ai besoin d'être en mesure de faire une recherche dans un laps de temps raisonnable.
Normale requête devrait ressembler à ceci:
db.lexemes.find({"wordforms.surface_form":"skrejjen"})
J'ai un index sur wordforms.surface_form
, et cette recherche est très rapide.
Cependant, si je veux avoir des jokers dans ma recherche, la performance est abyssmal. Par exemple:
db.lexemes.find({"wordforms.surface_form":/skrej/})
prend plus de 5 minutes (à ce moment je me gave d'attendre). Comme mentionné dans cette question, regex de la recherche sur les index est connu pour être mauvais. Je sais que l'ajout de l' ^ ancre dans la regex de recherches aide beaucoup, mais il a également sévèrement la limite de mes capacités de recherche. Même si je suis prêt à faire ce sacrifice, j'ai remarqué que le temps de réponse peut varier beaucoup en fonction de la regex. La requête
db.lexemes.find({"wordforms.surface_form":/^s/})
Prend 35s pour terminer.
Les meilleurs résultats que j'ai eu jusqu'à présent ont été, en fait, lorsque je désactive l'index à l'aide hint
.
Dans ce cas, les choses semblent s'améliorer considérablement. Cette requête:
db.lexemes.find({"wordforms.surface_form":/skrej/}).hint('_id_')
prend environ 3 secondes pour terminer.
Ma question est, est-il autre chose que je peux faire pour améliorer ces temps de recherche? Comme ils sont, ils sont encore un peu lent et je suis déjà envisagent la migration de MySQL dans l'espoir d'obtenir des performances. Mais je tiens vraiment à garder Mongo de flexibilité et d'éviter tous les fastidieux de la normalisation dans un SGBDR. Toutes les suggestions? Pensez-vous que je vais courir dans certains lenteur quel que soit le moteur DB, avec cette quantité de données de texte?
Je sais à propos de Mongo nouveau recherche de texte fonctionnalité, mais les avantages de cette (tokenisation et radical) ne sont pas pertinentes dans mon cas (pour ne pas mentionner ma langue n'est pas pris en charge). Il n'est pas clair si le texte de recherche est en fait plus rapide que l'utilisation de regex de toute façon.
Vous devez vous connecter pour publier un commentaire.
Une possibilité serait de stocker toutes les variantes que vous pensez pourrait être utile comme un élément de tableau — pas sûr que cela pourrait être possible si!
Je ne serais probablement aussi suggérer de ne pas les stocker 1000 mots à chaque mot, mais ce déplacer pour avoir des documents de petite taille. La plus petite de vos documents, le moins MongoDB aurait à lire dans la mémoire de recherche (aussi longtemps que les conditions de recherche ne nécessite pas une analyse complète de cours):
Je doute aussi que MySQL serait mieux ici avec des recherches par mot aléatoire formes qu'elle aura à faire un full table scan tout comme MongoDB serait. La seule chose qui pourrait l'aider il y a un cache de requêtes - mais c'est quelque chose que vous pouvez construire sur votre INTERFACE utilisateur de recherche/API dans votre application assez facilement, bien sûr.
Comme suggéré par Derick, j'ai refait les données dans ma base de données telle que je l'ai "wordforms" comme un ensemble plutôt que comme des sous-documents en vertu de la "lexèmes".
Les résultats ont fait mieux!
Voici un peu de vitesse des comparaisons. Le dernier exemple en utilisant
hint
est intentionnellement en contournant l'index sursurface_form
, qui, dans l'ancien schéma est effectivement plus rapide.Ancien schéma (voir question d'origine)
Nouveau schéma (voir Derick réponse)
Pour moi, c'est une bonne preuve qu'une refonte du schéma de rendre la recherche plus rapide, et de la valeur des données redondantes (ou extra rejoindre nécessaire).