Comment faire fonctionner les principales recherches de texte intégral génériques dans SQL Server ?

StackOverflow https://stackoverflow.com/questions/3400

  •  08-06-2019
  •  | 
  •  

Question

Note: je suis en utilisant les capacités de recherche en texte intégral de SQL, les clauses CONTAINS et tout - le * est le caractère générique en texte intégral, % est destiné aux clauses LIKE uniquement.

J'ai lu à plusieurs endroits maintenant que les recherches « principales caractères génériques » (par ex.l'utilisation de "*overflow" pour correspondre à "stackoverflow") n'est pas prise en charge dans MS SQL.J'envisage d'utiliser un Fonction CLR pour ajouter une correspondance d'expression régulière, mais je suis curieux de voir quelles autres solutions les gens pourraient avoir.

Plus d'informations: Vous pouvez ajouter l'astérisque uniquement à la fin du mot ou de la phrase. - avec mon expérience empirique :Lors de la correspondance avec "mavaleur", "mon*" fonctionne, mais "(astérisque)valeur" ne renvoie aucune correspondance, lors d'une requête aussi simple que :

SELECT * FROM TABLENAME WHERE CONTAINS(TextColumn, '"*searchterm"');

Ainsi, mon besoin d’une solution de contournement.J'utilise uniquement la recherche sur mon site sur une page de recherche réelle - elle doit donc fonctionner essentiellement de la même manière que Google (aux yeux d'un utilisateur de type Joe Sixpack).Pas aussi compliqué, mais ce genre de match ne devrait vraiment pas échouer.

Pas de solution correcte

Autres conseils

Solution de contournement uniquement pour le caractère générique principal :

  • stocker le texte inversé dans un champ différent (ou en vue matérialisée)
  • créer un index de texte intégral sur cette colonne
  • trouvez le texte inversé avec un *

    SELECT * 
    FROM TABLENAME 
    WHERE CONTAINS(TextColumnREV, '"mrethcraes*"');
    

Bien sûr, il existe de nombreux inconvénients, juste pour une solution de contournement rapide...

Sans parler de CONTAINSTABLE...

Le problème avec les principaux Wildcards :Ils ne peuvent pas être indexés, vous effectuez donc une analyse complète de la table.

Il est possible d'utiliser le caractère générique "*" à la fin du mot ou de la phrase (recherche par préfixe).

Par exemple, cette requête trouvera tous les "datab", "database", "databases"...

SELECT * FROM SomeTable WHERE CONTAINS(ColumnName, '"datab*"')

Mais malheureusement, il n'est pas possible d'effectuer une recherche avec un caractère générique de début.

Par exemple, cette requête ne trouvera pas « base de données »

SELECT * FROM SomeTable WHERE CONTAINS(ColumnName, '"*abase"')

Pour peut-être ajouter de la clarté à ce fil, d'après mes tests sur 2008 R2, Franjo a raison ci-dessus.Lorsqu'il s'agit d'une recherche en texte intégral, au moins lorsque vous utilisez la phrase CONTAINS, vous ne pouvez pas utiliser de début , seulement une fin fonctionnellement.* est le caractère générique, pas % dans le texte intégral.

Certains ont suggéré que * soit ignoré.Cela ne semble pas être le cas, mes résultats semblent montrer que la fonctionnalité de fin * fonctionne.Je pense que les premiers * sont ignorés par le moteur.

Mon problème supplémentaire est cependant que la même requête, avec un * final, qui utilise du texte intégral avec des caractères génériques a fonctionné relativement rapidement en 2005 (20 secondes) et a ralenti à 12 minutes après la migration de la base de données vers 2008 R2.Il semble qu'au moins un autre utilisateur ait eu des résultats similaires et il a lancé un message sur le forum auquel j'ai ajouté...FREETEXT fonctionne encore rapidement, mais quelque chose "semble" avoir changé avec la façon dont 2008 traite le * dans CONTAINS.Ils donnent toutes sortes d'avertissements dans le conseiller de mise à niveau indiquant qu'ils ont "amélioré" le TEXTE COMPLET afin que votre code puisse être défectueux, mais malheureusement, ils ne vous donnent aucun avertissement spécifique sur certains codes obsolètes, etc.... juste un avertissement indiquant qu'ils l'ont modifié, utilisez-le à vos propres risques.

http://social.msdn.microsoft.com/Forums/ar-SA/sqlsearch/thread/7e45b7e4-2061-4c89-af68-febd668f346c

C'est peut-être le problème MS le plus proche lié à ces problèmes... http://msdn.microsoft.com/en-us/library/ms143709.aspx

Une chose qu’il convient de garder à l’esprit est que les principales requêtes génériques entraînent une prime de performance significative par rapport aux autres utilisations de caractères génériques.

Le caractère générique dans SQL Server est le % signe et cela fonctionne très bien, en tête, en fin ou autre.

Cela dit, si vous envisagez d'effectuer une recherche sérieuse en texte intégral, j'envisagerais d'utiliser les fonctionnalités d'index de texte intégral.En utilisant % et _ les caractères génériques entraîneront une sérieuse baisse des performances de votre base de données.

À partir de la documentation en ligne de SQL Server :

Pour écrire des requêtes en texte intégral Microsoft SQL Server 2005, vous devez apprendre à utiliser les CONTAINS et FREETEXT Transact-SQL prédicats, et les fichiers CONTAINSTABLE et FREETEXTTABLE fonctions à valeur rowset.

Cela signifie que toutes les requêtes écrites ci-dessus avec % et _ ne sont pas des requêtes en texte intégral valides.

Voici un exemple de ce à quoi ressemble une requête lors de l’appel de la fonction CONTAINSTABLE.

SELECT RANK , * FROM TableName , CONTAINSTABLE (TableName, *, ' "*WildCard" ') searchTable WHERE [KEY] = TableName.pk ORDER BY searchTable.RANK DESC

Pour que la fonction CONTAINSTABLE sache que j'utilise une recherche générique, je dois la mettre entre guillemets.Je peux utiliser le caractère générique * au début ou à la fin.Vous pouvez faire beaucoup d'autres choses lorsque vous créez la chaîne de recherche pour la fonction CONTAINSTABLE.Vous pouvez rechercher un mot à proximité d'un autre mot, rechercher des mots flexionnels (drive = drives, conduit, conduisant et conduit) et rechercher un synonyme d'un autre mot (le métal peut avoir des synonymes tels que aluminium et acier).

Je viens de créer une table, de mettre un index de texte intégral sur la table et d'effectuer quelques recherches tests et je n'ai pas eu de problème, donc la recherche par caractère générique fonctionne comme prévu.

[Mise à jour]

Je vois que vous avez mis à jour votre question et savez que vous devez utiliser l'une des fonctions.

Vous pouvez toujours effectuer une recherche avec le caractère générique au début, mais si le mot n'est pas un mot complet après le caractère générique, vous devez ajouter un autre caractère générique à la fin.

Example:  "*ildcar" will look for a single word as long as it ends with "ildcar".

Example:  "*ildcar*" will look for a single word with "ildcar" in the middle, which means it will match "wildcard".  [Just noticed that Markdown removed the wildcard characters from the beginning and ending of my quoted string here.]

[Mise à jour n°2]

Dave Ward - L'utilisation d'un caractère générique avec l'une des fonctions ne devrait pas être un énorme succès en termes de performances.Si j'ai créé une chaîne de recherche avec juste "*", elle ne renverra pas toutes les lignes. Dans mon scénario de test, elle n'a renvoyé aucun enregistrement.

Juste pour information, Google n'effectue aucune recherche ni troncature de sous-chaînes, à droite ou à gauche.Ils comportent un caractère générique * pour rechercher des mots inconnus dans une phrase, mais pas un mot.

Google, comme la plupart des moteurs de recherche en texte intégral, établit un index inversé basé sur l'ordre alphabétique des mots, avec des liens vers leurs documents sources.La recherche binaire est très rapide, même pour des index volumineux.Mais il est vraiment très difficile de faire une troncature à gauche dans ce cas, car cela perd l'avantage de l'index.

En tant que paramètre dans une procédure stockée, vous pouvez l'utiliser comme :

ALTER procedure [dbo].[uspLkp_DrugProductSelectAllByName]
(
    @PROPRIETARY_NAME varchar(10)
)
as
    set nocount on
    declare @PROPRIETARY_NAME2 varchar(10) = '"' + @PROPRIETARY_NAME + '*"'

    select ldp.*, lkp.DRUG_PKG_ID
    from Lkp_DrugProduct ldp
    left outer join Lkp_DrugPackage lkp on ldp.DRUG_PROD_ID = lkp.DRUG_PROD_ID
    where contains(ldp.PROPRIETARY_NAME, @PROPRIETARY_NAME2)

Quand il s'agit de recherche en texte intégral, pour mon argent, rien ne vaut Lucène.Il y a un Port .Net disponible compatible avec les index créés avec la version Java.

La création/maintenance des index demande un peu de travail, mais la vitesse de recherche est fantastique et vous pouvez créer toutes sortes de requêtes intéressantes.Même la vitesse d'indexation est plutôt bonne : nous reconstruisons complètement nos index une fois par jour et ne nous soucions pas de leur mise à jour.

Par exemple, cette fonctionnalité de recherche est alimenté par Lucene.Net.

Peut-être que le lien suivant fournira la réponse finale à cette utilisation des caractères génériques : Effectuer des recherches FTS Wildcard.

Notez le passage qui dit :"Cependant, si vous précisez"Chaîne » ou « Chain », vous n’obtiendrez pas le résultat escompté.L'astérisque sera considéré comme un signe de ponctuation normal et non comme un caractère générique."

Si vous avez accès à la liste de mots du moteur de recherche en texte intégral, vous pouvez effectuer une recherche « j'aime » sur cette liste et faire correspondre la base de données avec les mots trouvés, par ex.un tableau 'mots' avec les mots suivants :

    pie
    applepie
    spies
    cherrypie
    dog
    cat

Pour faire correspondre tous les mots contenant 'tarte' dans cette base de données sur une table fts 'full_text' avec le champ 'text' :

    to-match <- SELECT word FROM words WHERE word LIKE '%pie%'
    matcher = ""
    a = ""
    foreach(m, to-match) {
      matcher += a
      matcher += m
      a = " OR "
    }
    SELECT text FROM full_text WHERE text MATCH matcher

% Correspond à n'importe quel nombre de caractères _ Correspond à un seul caractère

Je n'ai jamais utilisé l'indexation de texte intégral, mais vous pouvez effectuer des requêtes de recherche plutôt complexes et rapides en utilisant simplement les fonctions de chaîne T-SQL intégrées.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top