Avatar billede mjense173 Nybegynder
01. februar 2011 - 16:53 Der er 10 kommentarer og
1 løsning

Matche alle ord i en streng op mod nøgleord i en tabel.

Jeg har en lang streng. Det kunne eksempelvis være brødteksten i en email.

I min database har jeg registreret en masse nøgleord/tag, et ad gangen i en tabel: {id, tag}

Nu vil jeg gerne hente et recordset ud, med alle de nøgleord som står i strengen.

Hvordan gøres det mest optimalt? Det er jo ikke smart at lave et opslag for hvert ord i strengen?
Avatar billede hrc Mester
01. februar 2011 - 20:56 #1
Er det utænkeligt at du kan gøre det i et eller andet højniveau sprog?

Det forkromede alternativ er at indeksere brødteksten når det gemmes, altså gennemløbe den for tags og gemme dette resultat på en måde så du hurtigt kunne finde det i en søgning (sådan som eksempelvis et lille firma ved navn Google sikkert gør)
Altså en relation mellem mailen og de tags der rammer.

Eller lade en parallel process behandle alle data i baggrunden?
Avatar billede hrc Mester
01. februar 2011 - 20:57 #2
Ulempen er at hvis der tilføjes flere tags skal al data pløjes igennem igen. Altså noget med en baggrundsprocess.
Avatar billede jonatanpedersen Nybegynder
01. februar 2011 - 21:24 #3
Du kan skrive en User Defined Function til MS SQL i C#. Din funktion kunne f.eks. splitte din brødtekst op og returnere 1 row med hvert ord. Du kan så joine din tag tabel med din tabel fra UDFen.. Det burde virke fint til at hente tags for et enkelt stykke brødtekst.
Avatar billede hrc Mester
02. februar 2011 - 09:18 #4
jonatan: Ja, en eller anden højniveausprogsindgriben er vist nødvendig, enten i pre-/ baggrundsprocessering. Jeg vil prøve at kigge lidt her: http://tinyurl.com/6b8mssy.

Her på sidelinjen: Et lille spg. til Jonatan: Kan man i C# nedarve MSSQL datatyper, eks. VarBinary(max) til MyVarbinary(max)? Et ja/nej/"ved ikke" kan gøre det, bare så jeg kan fortsætte med eller droppe ideen. Jeg vil gerne lave en datatype som krypterer og gemmer data i fil hvis det er over 100kb, altså reelt ikke store ændringer i forhold til varbinary med filestrem aktiveret.
Avatar billede jonatanpedersen Nybegynder
02. februar 2011 - 11:09 #5
Jeg ved ikke om du kan nedarve dem.
Avatar billede beorndesign Nybegynder
02. februar 2011 - 21:59 #6
Du skal kigge på fulltext index. Det er det rette her. Du kan f.eks. lave din søgesætning med en UDF (funktion) eller blot smide al koden i en stored procedure.
En lang række 'LIKE' sætninger er for langsom på større databaser.

Lige et par links:
http://msdn.microsoft.com/en-us/library/ms142559.aspx
http://www.developer.com/db/article.php/3446891
Avatar billede beorndesign Nybegynder
02. februar 2011 - 22:06 #7
Et alternativ kunne være, at lave et loop i en stored procedure, som smider aller ordene ind i en midlertidig tabel (variabel: @tabel) - et ord pr. række:

Select ord FROM nøgleordTabel WHERE IN @tabel
Avatar billede mjense173 Nybegynder
31. marts 2011 - 00:23 #8
Jeg beklager at jeg har været så længe undervejs, men projektet har udviklet sig.

Jeg har brugt Jonas's idé med at konvertere en streng til en tabel. Til dette har jeg skrevet en Explode() funktion som splitter en streng op ved hvert mellemrum. (man kan evt. tage andre tegn med også, men i her er simpleste form)
Avatar billede mjense173 Nybegynder
31. marts 2011 - 00:24 #9
CREATE FUNCTION [explode](@text varchar(max), @delimiter nvarchar(1) = ' ')
RETURNS @words
TABLE
(
  wordnum int,
  word nvarchar(128),
  [ascii] int
)
AS
BEGIN

  DECLARE @i      AS INT
  DECLARE @wordnum  AS INT
  DECLARE @pointer  AS INT
  DECLARE @ascii    AS INT
  DECLARE @word    as nvarchar(128)
 
  SET    @text    = @text + ' e';
  SET    @i      = 1;
  SET    @wordnum  = 0;
  SET    @pointer  = 1;

  WHILE  @i <= LEN(@text)
  BEGIN
    IF SUBSTRING(@text,@i,1)= @delimiter
    BEGIN
      SET @word = LTRIM(RTRIM(SUBSTRING(@text,@pointer,(@i-@pointer))))
      IF(LEN(@word) > 0)
      BEGIN
        IF(LEN(@word)=1)
          SET @ascii = ASCII(@word);
        ELSE
          SET @ascii = 0;
        SET @wordnum = @wordnum + 1;
        IF(NOT EXISTS (SELECT * FROM @words WHERE word = @word))
          INSERT INTO @words (wordnum,word,[ascii]) VALUES (@wordnum,LTRIM(RTRIM(@word)),@ascii);
      END
      SET @pointer = @i + 1
    END
    SET @i = @i + 1
  END
  RETURN
END
Avatar billede mjense173 Nybegynder
31. marts 2011 - 00:26 #10
Herefter er det blot at matche tabellen op mod tags-listen via en anden funktion. Man kan så optimere det ved at have index på begge tabeller. (kræver dog at det køres i en SP)
Avatar billede mjense173 Nybegynder
31. marts 2011 - 00:27 #11
Dem der mener de har fortjent point, må gerne smide et svar :-)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester