Inlämningsuppgift : Finn 2D1418 Språkteknologi Christoffer Sabel E-post: csabel@kth.se 1
1. Inledning...3 2. Teori...3 2.1 Termdokumentmatrisen...3 2.2 Finn...4 3. Implementation...4 3.1 Databasen...4 3.2 Algoritm för att skapa en databas...5 3.3 Algoritm för att söka i en databas...5 3.4 Tokstem...6 3.5 Förbättringar...6 2
1. Inledning Om man har en stor textmängd, t ex artiklar, är det vanligt att man vill kunna söka bland dessa efter specifika ord. Då är det vanligt att man skapar ett index som är en form av databas. Frågan är då: hur fungerar egentligen ett index. För att lära mig det har jag skapat ett program som jag kallar Finn. Finn har två funktioner: 1) Utifrån vissa textfiler skapar man ett index i form av tre stycken filer. 2) Sedan kan man använda dessa filer med Finn för att söka efter i vilka texter som olika ord förekommer. Sökresultaten sorteras sedan efter hur viktiga sökorden anses vara i de olika texterna. För att avgöra hur viktigt ett visst ord är i en text så brukar man beräkna hur stor andelen av alla ord i texten är just det man söker efter. Ifall ett ord nämns ofta i en text så anses det viktigt för vad texten handlar om och ger därför ett högre värde. Man kan även låta ord som inte förekommer i så många texter få ett högre värde. 2. Teori 2.1 Termdokumentmatrisen För att kunna söka på ord i textmängderna så behöver man spara statistisk data över hur orden förekommer i de olika texterna. Det sparas i en matris där varje rad motsvarar ett unikt ord och varje kolumn en text. Vad man använder för statistik kan variera men två vanliga mått är: i = Rad. j = Kolumn. N = Antal texter i mängden. n = Antal texter som ordet (i) förekommer i. i m i, j = Antal förekomster av ordet (i) i texten (j). M j = Antal ord i text (j). Termfrekvens mi, j tf i, j = M j Hur stor andel av orden i text (j) är ordet (i). Inversdokumentfrekvens N idf = i log ni Ord som inte förekommer i så många olika texter får ett större värde, dom är ovanliga och ska därför betraktas som viktigare ifall man söker på dom. 3
2.2 Finn Finn sparar tf*idf som statistiskt mått i sin termdokumentmatris. Inversdokumentfrekvensen har bara betydelse ifall man gör en sökning på flera ord samtidigt, annars så skalar den bara om värdena utan att påverka vilken text klassas som bästa söksvar. Finn är egentligen två program, först så kan den skapa databas filer utifrån en mängd källfiler och sedan så kan man göra en sökning efter ord i specificerad databas. Skapa databas finn i [VALMÖJLIGHETER]* [DBNAMN] [FILLISTA] VALMÖJLIGHETER: -mx Begränsa antalet källfiler till X. -s Använd endast ordstammen. -o Låt ovanliga ord få en högre vikt. FILLISTA: Fil innehållande en lista över vilka filer som ska indexeras. Varje rad innehåller fullständigt namn på en fil att använda. DBNAMN: Basnamn för filerna som utgör databasen. Sök efter ord finn f [DBNAMN] DBNAMN: Basnamn för filerna som utgör databasen. 3. Implementation Efter att snabbt ha gått igenom teorin bakom hur sökmotorn Finn fungerar så ska det här avsnittet beskriva hur implementationen är gjord. Avslutningsvis så beskrivs några förslag hur man kan modifiera Finn för bättre prestanda och funktionalitet. 3.1 Databasen Databasen för textmängden är i grund och botten Termdokumentmatrisen som man har lagrat på ett effektivt sätt. Det är opraktiskt att spara alla fält i matrisen eftersom majoriteten kommer att innehålla nollor, det är inte ofta det finns en text som innehåller alla ord. Exempel: Vi har 60 texter som tillsammans innehåller 3000 olika ord, för att spara denna matris skulle man behöva 180000*storlek_att_spara_ett_fält med minne. Man tittar närmare på matrisen och ser att varje text innehåller i genomsnitt 50 olika ord, för att spara detta behöver man endast 3000*storlek_att_spara_ett_fält med minne. Att spara matrisen på det sista sättet kräver endast 1.7% av minnet som det första. 4
I Finn sparas matrisen i tre stycken filer med samma basnamn:.words Varje unikt ord sparas i en datastruktur. 1) Ordet i textform (max 19 tecken). 2) Varje ord tilldelas ett unikt nummer (som de andra filerna sedan använder). Orden sparas sorterade så att det går att använda binärsökning när man ska ta reda på de unika numren för sökorden..files Varje text läses från fil och sparas i en datastruktur. 1) Namn på filen, inklusive sökväg (max 127 tecken). 2) Var i index filen som orden för den här texten börjar. 3) Antal ord (rader i matrisen) som ska läsas in..index Här sparas förekomsterna för orden i de olika texterna (matrisdata). 1) Ordets unika nummer. 2) Vikt som det här ordet har i texten. Alla delar som tillhör en och samma text sorteras efter ordets nummer för att göra sökningen effektivare. 3.2 Algoritm för att skapa en databas För att sökningen ska bli bättre så kan man säga åt Finn att spara ordens stam istället för hela formen, detta gör att t ex bilen och bilarna räknas som samma ord bil. För att dela upp en text i ord (eventuellt stammen) så använder jag ett program. Sedan tar jag svaret från det och kör ett antal unix kommandon (cut, sort, uniq) för att få texten i den form jag vill ha. Pseudo kod För varje text i indata. Skapa lista över orden och antal förekomster. För varje ord Är det ett nytt ord. Lägg till i den globala ordlistan. Ge det ett unikt nummer. Spara ordet till.index. Spara filnamn, var i.index det första ordet sparades och antal ord i texten till.files. Sortera den globala ordlistan och spara den till.words. 3.3 Algoritm för att söka i en databas Man kan söka på ett eller flera ord åt gången. Det går till så att man skapar en vektor med alla sökorden. Sedan multipliceras den med varje kolumn i matrisen, och de resultat som är större än noll sparas som svarsresultat (i sorterad ordning så högst värde först). 5
Pseudo kod För varje ord i söksträngen. Använd binärsökning för att hitta ordet i.words och spara dess nummer (om det finns). Skapa en vektor med alla nummer och sortera den. För varje text i.files Beräkna totala vikt genom att summera värdena för varje sökord som finns i texten. Sortera och skriv ut namnet på alla texter som hade en vikt större än noll. Anledning till att jag sorterar de olika vektorerna efter ordens nummer är att det går snabbare att jämföra två sorterade vektorer än osorterade. Om mängden av tal i vektorerna inte överlappar varandra så behöver man inte göra några jämförelser. 3.4 Tokstem Som jag nämnde i 3.2 så använder Finn ett program som heter tokstem för att plocka ut de olika orden från en text (den klarar av att ta bort html taggar). Ifall s flaggan används när man skapar databasen så ska bara stammen för varje ord användas, och det ordnar tokstem automatiskt. Finn fungerar bara ifall tokstem finns tillgängligt från katalogen man arbetar i. Tokstem är skapat av Magnus Rosell rosell@nada.kth.se, det i sin tur använder sig utav två andra verktyg som är utvecklade på nada: 1) Stava, av Viggo Kann och Joachim Hollman. 2) En svensk stemmer av Johan Carlberger. 3.5 Förbättringar Som med dom flesta program finns det saker man kan göra för att effektivisera Finn. Två viktiga egenskaper för en sökmotor är mängden minne och tid den behöver för att skapa databasen. Minne (hårddisk) Varje ord i.words och filnamn i.files lagras med förbestämd storlek oavsett hur många tecken som används. Detta är slöseri på minne då de allra flesta strängar använder betydligt färre tecken. Man skulle kunna låta strängar ha varierande längd, men det har som nackdel att det blir svårare att söka i filerna och baskostnaden (i minne) för att spara en sträng kan öka en aning. Finn läser det mesta av data från filerna när den behöver dom, det är bara vid skapandet av ordlistan som alla unika ord sparas i minnet. Därför så har Finn inte så höga minneskrav annat än för hårddisken. Tid att skapa databaser Tokstem anropas för varje textfil vilket innebär att en ny process hela tiden måste skapas. Jag vet inte hur tokstem är skrivet men ifall det kräver någon sorts initiering så kommer den att köras en gång för varje textfil som ska läsas, vilket är slöseri på tid. För att förbättra det skulle man kunna gruppera textfiler och låta tokstem bearbeta flera åt gången, men då blir det samtidigt svårare att läsa in. Beroende på vilken funktionalitet tokstem har så kan man effektivisera på olika sätt. Att implementera funktionaliteten som tokstem ger direkt i Finn skulle öka effektiviteten, men komplexiteten för programmet skulle även det öka. 6
Söktid Den nuvarande implementationen sparar kolumnerna i termdokumentmatrisen. För att effektivisera söktiden så skulle man eventuellt kunna spara raderna istället. Då behöver man bara gå igenom en lista för varje sökord (som finns sparad på fil) och notera de filerna som söksvar. Man måste skriva lite extra kod för att sökning på flera ord ska fungera. Men att spara matrisen på det här sättet gör att det blir mycket svårare att jämföra hur lika två texter är. Eventuellt skulle man kunna spara båda varianterna, men minneskraven skulle då öka. Att spara vilka ord som förekommer i en text kallas framåt indexering. Invers indexering är tvärtom, man sparar vilka texter ett visst ord förekommer i. Finn använder sig utav framåt indexering vilket egentligen passar bättre för att jämföra texter än att söka efter ord. Men utifrån ett framåt index kan man skapa ett invers index ifall man skulle vilja bygga vidare på programmet. Finn var konstruerat som ett enkelt testprogram, och någonstans måste man dra gränsen för vad som räcker att implementera. Flera filer till en För att kod och exekvering ska vara överskådlig så har de olika delarna sparats i separata filer. Man skulle kunna kombinera alla filerna till en enda fil för att ha all data samlad. 7