Utilisation de la recherche en texte intégral dans SQL Server 2008 sur plusieurs tables et colonnes

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

Question

Je dois effectuer une recherche dans plusieurs colonnes de deux tables de ma base de données à l'aide de la recherche en texte intégral. Les deux tables en question ont les colonnes correspondantes indexées en texte intégral.

La raison pour laquelle j'ai opté pour la recherche en texte intégral: 1. Pour pouvoir rechercher facilement des mots accentués (café) 2. Etre capable de classer selon la proximité des mots, etc. 3. "Voulez-vous dire XXX?" fonctionnalité

Voici une structure factice pour illustrer le défi:

Table Book
BookID
Name (Full-text indexed)
Notes (Full-text indexed)

Table Shelf
ShelfID
BookID

Table ShelfAuthor
AuthorID
ShelfID

Table Author
AuthorID
Name (Full-text indexed)

Je dois effectuer une recherche dans le nom du livre, les notes du livre et le nom de l'auteur.

Je connais deux méthodes pour y parvenir:

  1. Utilisation d'une vue indexée en texte intégral: cela aurait été ma méthode préférée, mais je ne peux pas le faire car, pour qu'une vue soit indexée en texte intégral, elle doit être schemabound, ne pas avoir de jointures externes, avoir un index unique. La vue dont j'aurai besoin pour récupérer mes données ne répond pas à ces contraintes (elle contient de nombreuses autres tables jointes dont je dois extraire des données).

  2. Utilisation de jointures dans une procédure stockée : le problème de cette approche est que les résultats doivent être triés par rang. Si je fais plusieurs jointures dans les tables, SQL Server ne recherchera pas dans plusieurs champs par défaut. Je peux combiner deux requêtes CONTAINS individuelles sur les deux tables liées, mais je ne connais aucun moyen d'extraire le classement combiné des deux requêtes de recherche. Par exemple, si je recherche 'Arthur', les résultats de la requête Livre et de la requête Auteur doivent être pris en compte et pondérés en conséquence.

Était-ce utile?

La solution

Avec FREETEXTTABLE, il vous suffit de concevoir un algorithme pour calculer le classement fusionné sur chaque résultat de la table jointe. L’exemple ci-dessous oriente le résultat vers les résultats de la table des livres.

SELECT b.Name, a.Name, bkt.[Rank] + akt.[Rank]/2 AS [Rank]
FROM Book b
INNER JOIN Author a ON b.AuthorID = a.AuthorID
INNER JOIN FREETEXTTABLE(Book, Name, @criteria) bkt ON b.ContentID = bkt.[Key] 
LEFT JOIN FREETEXTTABLE(Author, Name, @criteria) akt ON a.AuthorID = akt.[Key]
ORDER BY [Rank] DESC

Notez que j'ai simplifié votre schéma pour cet exemple.

Autres conseils

J'ai eu le même problème que vous mais il s'agissait en fait de 10 tables (une table Utilisateurs et plusieurs autres pour information)

J'ai fait ma première requête en utilisant FREETEXT dans la clause WHERE pour chaque table, mais la requête prenait beaucoup trop de temps.

J'ai ensuite vu plusieurs réponses concernant l'utilisation de FREETEXTTABLE à la place et la recherche de valeurs non nulles dans la colonne de clé pour chaque table, mais cela a également pris beaucoup de temps à s'exécuter.

Je l'ai corrigé en utilisant une combinaison de FREETEXTTABLE et UNION sélectionne:

SELECT Users.* FROM Users INNER JOIN
(SELECT Users.UserId FROM Users INNER JOIN FREETEXTTABLE(Users, (column1, column2), @variableWithSearchTerm) UsersFT ON Users.UserId = UsersFT.key
UNION
SELECT Table1.UserId FROM Table1 INNER JOIN FREETEXTTABLE(Table1, TextColumn, @variableWithSearchTerm) Table1FT ON Table1.UserId = Table1FT.key
UNION
SELECT Table2.UserId FROM Table2 INNER JOIN FREETEXTTABLE(Table2, TextColumn, @variableWithSearchTerm) Table2FT ON Table2.UserId = Table2FT.key
... --same for all tables
) fts ON Users.UserId = fts.UserId

Cela s'est avéré incroyablement beaucoup plus rapide.

J'espère que cela vous aidera.

Je ne pense pas que la réponse acceptée résoudra le problème. Si vous essayez de trouver tous les livres d'un certain auteur et utilisez par conséquent le nom de l'auteur (ou une partie de celui-ci) comme critère de recherche, les seuls livres renvoyés par la requête seront ceux dont le critère de recherche porte son propre nom. .

La seule façon pour moi de résoudre ce problème consiste à répliquer les colonnes de l'auteur sur lesquelles vous souhaitez effectuer une recherche dans la table Book et à indexer ces colonnes (ou colonne, car il serait probablement judicieux de stocker les informations pertinentes de l'auteur dans une colonne XML). dans la table des livres).

FWIW, dans une situation similaire, notre DBA a créé des déclencheurs DML afin de maintenir une table de recherche en texte intégral dédiée. Il n’était pas possible d’utiliser une vue matérialisée à cause de ses nombreuses restrictions.

Je voudrais utiliser une procédure stockée. La méthode de texte intégral ou quoi que ce soit retourne un classement dans lequel vous pouvez trier. Je ne suis pas sûr de savoir comment ils vont être comparés, mais je suis sûr que vous pourriez bricoler pendant un moment et résoudre le problème. Par exemple:

Select SearchResults.key, SearchResults.rank From FREETEXTTABLE(myColumn, *, @searchString) as SearchResults Order By SearchResults.rank Desc

Cette réponse est attendue depuis longtemps, mais si vous ne pouvez pas modifier les tables primaires, vous pouvez créer une nouvelle table avec les paramètres de recherche ajoutés à une colonne.

Créez ensuite un index de texte intégral sur cette colonne et interrogez cette colonne.

Exemple

SELECT 
    FT_TBL.[EANHotelID]                 AS HotelID, 
    ISNULL(FT_TBL.[Name],'-')           AS HotelName,
    ISNULL(FT_TBL.[Address1],'-')       AS HotelAddress,
    ISNULL(FT_TBL.[City],'-')           AS HotelCity,
    ISNULL(FT_TBL.[StateProvince],'-')  AS HotelCountyState,
    ISNULL(FT_TBL.[PostalCode],'-')     AS HotelPostZipCode,
    ISNULL(FT_TBL.[Latitude],0.00)      AS HotelLatitude,
    ISNULL(FT_TBL.[Longitude],0.00)     AS HotelLongitude,
    ISNULL(FT_TBL.[CheckInTime],'-')    AS HotelCheckinTime,
    ISNULL(FT_TBL.[CheckOutTime],'-')   AS HotelCheckOutTime,
    ISNULL(b.[CountryName],'-')         AS HotelCountry,
    ISNULL(c.PropertyDescription,'-')   AS HotelDescription,
    KEY_TBL.RANK 

    FROM [EAN].[dbo].[tblactivepropertylist] AS FT_TBL INNER JOIN
     CONTAINSTABLE ([EAN].[dbo].[tblEanFullTextSearch], FullTextSearchColumn, @s)
      AS KEY_TBL
    ON FT_TBL.EANHotelID = KEY_TBL.[KEY]
    INNER JOIN [EAN].[dbo].[tblCountrylist] b
    ON FT_TBL.Country = b.CountryCode
    INNER JOIN [EAN].[dbo].[tblPropertyDescriptionList] c
    ON FT_TBL.[EANHotelID] = c.EANHotelID

Dans le code ci-dessus [EAN]. [dbo]. [tblEanFullTextSearch], FullTextSearchColumn est la nouvelle table et la nouvelle colonne avec les champs ajoutés, vous pouvez désormais effectuer une requête sur la nouvelle table avec des jointures à la table que vous souhaitez afficher. les données de.

J'espère que cela vous aidera

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