2008-10-14 11 views
12

Je construis une application C#/ASP.NET avec un backend SQL. Je suis à la date limite et finissant mes pages, sur le champ de gauche un de mes designers a incorporé une recherche en texte intégral sur une de mes pages. Mes "recherches" jusqu'à ce point ont été des filtres, étant capable de réduire un ensemble de résultats par certains facteurs et valeurs de colonne. Étant donné que je suis à la date limite (vous savez 3 heures de sommeil par nuit, au point où je ressemble à quelque chose que le chat a mangé et vomi), je m'attendais à ce que cette page soit très similaire à d'autres et J'essaie de décider de faire ou non une puanteur. Je n'ai jamais fait de recherche en texte intégral sur une page avant ... Est-ce une montagne à escalader ou existe-t-il une solution simple?À quel point est-il difficile d'incorporer la recherche en texte intégral avec SQL Server?

merci.

Répondre

27

Tout d'abord, vous devez permis Texte intégral indexation Recherche sur les serveurs de production, donc si ce n'est pas dans la portée, vous ne voudrez pas aller avec cela.

Cependant, si cela est déjà prêt, la recherche en texte intégral est relativement simple.

T-SQL dispose de 4 prédicats utilisés pour la recherche en texte intégral:

  • FREETEXT
  • FREETEXTTABLE
  • CONTIENT
  • CONTAINSTABLE

FREETEXT est la plus simple et peut se faire comme ceci:

SELECT UserName 
FROM Tbl_Users 
WHERE FREETEXT (UserName, 'bob') 

Results: 

JimBob 
Little Bobby Tables 

FREETEXTTABLE fonctionne de la même manière que FreeTEXT, sauf qu'il renvoie les résultats sous forme de tableau.

La puissance réelle de recherche en texte intégral de T-SQL provient de la CONTIENT (et CONTAINSTABLE) prédicat ... Celui-ci est énorme, donc je vais juste coller son utilisation dans:

CONTAINS 
    ({ column | * } , '<contains_search_condition>' 
    ) 

<contains_search_condition> ::= 
     { <simple_term> 
     | <prefix_term> 
     | <generation_term> 
     | <proximity_term> 
     | <weighted_term> 
     } 
     | { (<contains_search_condition>) 
     { AND | AND NOT | OR } <contains_search_condition> [ ...n ] 
     } 

<simple_term> ::= 
    word | " phrase " 

< prefix term > ::= 
    { "word * " | "phrase * " } 

<generation_term> ::= 
    FORMSOF (INFLECTIONAL , <simple_term> [ ,...n ]) 

<proximity_term> ::= 
    { <simple_term> | <prefix_term> } 
    { { NEAR | ~ } { <simple_term> | <prefix_term> } } [ ...n ] 

<weighted_term> ::= 
    ISABOUT 
     ({ { 
       <simple_term> 
       | <prefix_term> 
       | <generation_term> 
       | <proximity_term> 
       } 
      [ WEIGHT (weight_value) ] 
      } [ ,...n ] 
     ) 

Ce moyen vous pouvez écrire des requêtes telles que:

SELECT UserName 
FROM Tbl_Users 
WHERE CONTAINS(UserName, '"little*" NEAR tables') 

Results: 

Little Bobby Tables 

Bonne chance :)

+4

J'ai voté ceci et l'a excepté comme réponse non seulement parce que c'est une réponse grande et détaillée mais également pour la référence de xkcd. GAGNER. –

0

"Quelle est la difficulté" est une question difficile à répondre. Par exemple, quelqu'un qui l'a déjà fait 10 fois va probablement penser que c'est un jeu d'enfant. Tout ce que je peux vraiment dire, c'est que vous êtes susceptible de trouver cela beaucoup plus facile si vous utilisez quelque chose comme NLucene plutôt que de rouler les vôtres.

2

La recherche de texte complet dans SQL Server est vraiment facile, un peu de configuration et un léger tweak sur le queryside et vous êtes prêt à partir! Je l'ai fait pour les clients en moins de 20 minutes avant, être familier avec le processus

Voici le 2008 MSDN article, les liens vont vers les versions 2005 de là

2

Je l'ai utilisé dtSearch avant d'ajouter recherche de texte intégral aux fichiers et bases de données, et leurs trucs est assez facile et pas cher t o utiliser. En plus d'ajouter tout cela et de configurer SQL, ce script va chercher dans toutes les colonnes d'une base de données et vous dire quelles colonnes contiennent les valeurs que vous recherchez.

Je sais que ce n'est pas la solution "appropriée", mais peut vous acheter du temps.

/*This script will find any text value in the database*/ 
/*Output will be directed to the Messages window. Don't forget to look there!!!*/ 

SET NOCOUNT ON 
DECLARE @valuetosearchfor varchar(128), @objectOwner varchar(64) 
SET @valuetosearchfor = '%staff%' --should be formatted as a like search 
SET @objectOwner = 'dbo' 

DECLARE @potentialcolumns TABLE (id int IDENTITY, sql varchar(4000)) 

INSERT INTO @potentialcolumns (sql) 
SELECT 
    ('if exists (select 1 from [' + 
    [tabs].[table_schema] + '].[' + 
    [tabs].[table_name] + 
    '] (NOLOCK) where [' + 
    [cols].[column_name] + 
    '] like ''' + @valuetosearchfor + ''') print ''SELECT * FROM [' + 
    [tabs].[table_schema] + '].[' + 
    [tabs].[table_name] + 
    '] (NOLOCK) WHERE [' + 
    [cols].[column_name] + 
    '] LIKE ''''' + @valuetosearchfor + '''''' + 
    '''') as 'sql' 
FROM information_schema.columns cols 
    INNER JOIN information_schema.tables tabs 
     ON cols.TABLE_CATALOG = tabs.TABLE_CATALOG 
      AND cols.TABLE_SCHEMA = tabs.TABLE_SCHEMA 
      AND cols.TABLE_NAME = tabs.TABLE_NAME 
WHERE cols.data_type IN ('char', 'varchar', 'nvchar', 'nvarchar','text','ntext') 
    AND tabs.table_schema = @objectOwner 
    AND tabs.TABLE_TYPE = 'BASE TABLE' 
ORDER BY tabs.table_catalog, tabs.table_name, cols.ordinal_position 

DECLARE @count int 
SET @count = (SELECT MAX(id) FROM @potentialcolumns) 
PRINT 'Found ' + CAST(@count as varchar) + ' potential columns.' 
PRINT 'Beginning scan...' 
PRINT '' 
PRINT 'These columns contain the values being searched for...' 
PRINT '' 
DECLARE @iterator int, @sql varchar(4000) 
SET @iterator = 1 
WHILE @iterator <= (SELECT Max(id) FROM @potentialcolumns) 
BEGIN 
    SET @sql = (SELECT [sql] FROM @potentialcolumns where [id] = @iterator) 
    IF (@sql IS NOT NULL) and (RTRIM(LTRIM(@sql)) <> '') 
    BEGIN 
     --SELECT @sql --use when checking sql output 
     EXEC (@sql) 
    END 
    SET @iterator = @iterator + 1 
END 

PRINT '' 
PRINT 'Scan completed' 
1

J'ai été là. Cela fonctionne comme un charme jusqu'à ce que vous commenciez à considérer l'évolutivité et les fonctionnalités de recherche avancées comme la recherche sur plusieurs colonnes avec des valeurs de poids différentes.

Par exemple, la seule façon de rechercher sur Titre et Résumé colonnes est d'avoir une colonne calculée avec SearchColumn = CONCAT(Title, Summary) et l'index sur SearchColumn. Pondération SearchColumn = CONCAT(CONCAT(Title,Title), Summary) quelque chose comme ça. ;) Filtrage? Oublie ça.

Questions connexes