Tor Jarle Sagen Stig Runar Vangen



Like dokumenter
Algoritmer - definisjon

Algoritmeanalyse. (og litt om datastrukturer)

Søkemaskiner. Svein Arne Haug Ståle A. Nygård

Ordliste. Obligatorisk oppgave 1 - Inf 1020

EKSAMEN. Dato: 9. mai 2016 Eksamenstid: 09:00 13:00

TOD063 Datastrukturer og algoritmer

TDT4102 Prosedyre og Objektorientert programmering Vår 2014

Obligatorisk oppgave 1 INF1020 h2005

Oblig 4 (av 4) INF1000, høsten 2012 Værdata, leveres innen 9. nov. kl

Algoritmer og datastrukturer Kapittel 9 - Delkapittel 9.1

Oppgavesettet består av 7 sider, inkludert denne forsiden. Kontroll& at oppgaven er komplett før du begynner å besvare spørsmålene.

TDT4102 Prosedyreog objektorientert programmering Vår 2016

Kompleksitetsanalyse Helge Hafting Opphavsrett: Forfatter og Stiftelsen TISIP Lærestoffet er utviklet for faget LO117D Algoritmiske metoder

TOD063 Datastrukturer og algoritmer

Dagens tema: 12 gode råd for en kompilatorskriver. Sjekking av navn. Lagring av navn. Hvordan finne et navn?

Algoritmer og datastrukturer Kapittel 9 - Delkapittel 9.2

Algoritmer og Datastrukturer

Løse reelle problemer

LITT OM OPPLEGGET. INF1000 EKSTRATILBUD Stoff fra uke September 2012 Siri Moe Jensen EKSEMPLER

Kanter, kanter, mange mangekanter

EKSAMEN. Dato: 28. mai 2018 Eksamenstid: 09:00 13:00

EKSAMEN. Dato: 18. mai 2017 Eksamenstid: 09:00 13:00

Rekursiv programmering

EKSAMEN. Algoritmer og datastrukturer. Eksamensoppgaven: Oppgavesettet består av 11 sider inklusiv vedlegg og denne forsiden.

... Når internminnet blir for lite. Dagens plan: Løsning: Utvidbar hashing. hash(x) katalog. O modellen er ikke lenger gyldig ved

Algoritmer og Datastrukturer IAI 21899

Introduksjon til objektorientert. programmering. Hva skjedde ~1967? Lokale (og globale) helter. Grunnkurs i objektorientert.

ITF20006 Algoritmer og datastrukturer Oppgavesett 7

INF1020 Algoritmer og datastrukturer

Python: Oppslagslister (dictionaries) og mengder 3. utgave: Kapittel 9

Endret litt som ukeoppgave i INF1010 våren 2004

Hashing. INF Algoritmer og datastrukturer HASHING. Hashtabeller

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister

Algoritmer og Datastrukturer

Eksamen i emnet INF100 Grunnkurs i programmering (Programmering I) og i emnet INF100-F Objektorientert programmering i Java I

Algoritmer og datastrukturer A.1 Filbehandling på bit-nivå

Algoritmer og Datastrukturer

Algoritmer og datastrukturer Kapittel 1 - Delkapittel 1.3

... HASHING. Hashing. Hashtabeller. hash(x)

Rekursjon. Binærsøk. Hanois tårn.

Tre måter å lese fra terminal. Java 4. Eksempel. Formatert utskrift til skjerm

while-økker while-løkker gjentar instruksjonene så lenge en betingelse er oppfylt Eksempel 1: en enkel while-løkke

INF Algoritmer og datastrukturer

Maps og Hashing. INF Algoritmer og datastrukturer. Map - ADT. Map vs Array

Korteste vei i en vektet graf uten negative kanter

Lese fra fil. INF1000 : Forelesning 5. Eksempel. De vanligste lesemetodene. Metoder:

Høst Øving 5. 1 Teori. 2 Månedskalender. Norges teknisknaturvitenskapelige universitet Institutt for datateknikk og informasjonsvitenskap

3 emner i dag! INF1000 Uke 5. Objekter og pekere. null. Litt om objekter, pekere og null Filer og easyio Litt mer om tekster

Oppgave 1. Sekvenser (20%)

programeksempel Et større En større problemstilling Plan for forelesingen Problemstillingen (en tekstfil) inneholdt ordet "TGA"

INF2220: Forelesning 3

INF2220: Forelesning 3. Map og hashing Abstrakte datatyper (kapittel 3.1) Map (kapittel 4.8) Hashing (kapittel 5)

Løsnings forslag i java In115, Våren 1996

UNIVERSITETET I OSLO

Et eksempel: Åtterspillet

Innhold uke 4. INF 1000 høsten 2011 Uke 4: 13. september. Deklarasjon av peker og opprettelse av arrayobjektet. Representasjon av array i Java

Maps og Hashing. INF Algoritmer og datastrukturer. Map - ADT. Map vs Array

INF109 - Uke 1b

Algoritmer og datastrukturer Kapittel 11 - Delkapittel 11.2

UNIVERSITETET I OSLO

UNIVERSITETET I OSLO

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister Videre

Søkeproblemet. Gitt en datastruktur med n elementer: Finnes et bestemt element (eller en bestemt verdi) x lagret i datastrukturen eller ikke?

Ny/utsatt EKSAMEN. Dato: 6. januar 2017 Eksamenstid: 09:00 13:00

Kapittel 14, Hashing. Tema. Definere hashing Studere ulike hashfunksjoner Studere kollisjonsproblemet 17-1

UNIVERSITETET I OSLO

Utførelse av programmer, metoder og synlighet av variabler i JSP

Hashtabeller. Lars Vidar Magnusson Kapittel 11 Direkte adressering Hashtabeller Chaining Åpen-adressering

Norsk informatikkolympiade runde

Programmering Høst 2017

Datastrukturer for rask søking

Oppgave 1 a. INF1020 Algoritmer og datastrukturer. Oppgave 1 b

Python: Løkker. TDT4110 IT Grunnkurs Professor Guttorm Sindre

NITH PG4200 Algoritmer og datastrukturer Løsningsforslag Eksamen 4.juni 2013

TDT4100 Objektorientert programmering

INF1010 LISTER. Listeelementer og listeoperasjoner. Foran. Bak

Forelesningsquiz. Forelesning inf Java 5. Sett dere to (eller tre) sammen og besvar de fire spørsmålene på utdelt ark. Tid: 15 min.

EKSAMEN. Emne: Algoritmer og datastrukturer

Løsningsforslag EKSAMEN

INF oktober Dagens tema: Uavgjørbarhet. Neste uke: NP-kompletthet

Liste som abstrakt konsept/datatype

BOKMÅL Side 1 av 5. KONTERINGSEKSAMEN I FAG TDT4102 Prosedyre og objektorientert programmering. Onsdag 6. august 2008 Kl

Enkle generiske klasser i Java

UNIVERSITETET I OSLO

EKSAMEN 6108/6108N PROGRAMMERING I JAVA Alt trykt og skriftlig materiale.

Ta inn og ut av 2D-array. Java 6. Liste over ulike verdier i 2D-array. Det ferdige programmet. Vi skal lage et program som illustrerer hvordan man

UNIVERSITETET I OSLO

UNIVERSITETET. Indeksering. Konvensjonelle indekser B-trær og hashing Flerdimensjonale indekser Hashliknende strukturer.

INF1000 EKSTRATILBUD. Stoff fra uke 1-5 (6) 3. oktober 2012 Siri Moe Jensen

UNIVERSITETET I OSLO

Løsningsforslag ukeoppg. 6: 28. sep - 4. okt (INF Høst 2011)

INF2220: Forelesning 2

Norsk informatikkolympiade runde

TDT4105 Informasjonsteknologi, grunnkurs

E K S A M E N. Algoritmiske metoder I. EKSAMENSDATO: 11. desember HINDA / 00HINDB / 00HINEA ( 2DA / 2DB / 2EA ) TID:

Hashing: Håndtering av kollisjoner

81,9(56,7(7(7,26/2 'HWPDWHPDWLVNQDWXUYLWHQVNDSHOLJHIDNXOWHW

Redd verden. Steg 1: Legg til Ronny og søppelet. Sjekkliste. Introduksjon

INF1010 notat: Binærsøking og quicksort

TDT4110 Informasjonsteknologi grunnkurs: Kapittel 7 Filer og unntak ( exceptions ) Professor Alf Inge Wang Stipendiat Lars Bungum

Transkript:

Tor Jarle Sagen Stig Runar Vangen Søkemaskiner Høsten 2003 Avdeling for samfunn, næring og natur

Forord Denne rapport er utarbeidet høsten 2003 ved HINT/ITU, som en del av faget CIT 510 Søkemaskiner. Personene bak denne rapporten er Stig Runar Vangen og Tor Jarle Sagen. Faglærer har vært Stephen Alstrup. Målet med dette faget har vært å lære grunnleggende virkemåte og programmering av søkemaskiner. Som utgangspunkt for arbeidet fikk vi utlevert koden til en enkel søkemaskin programmert i Java. Vårt arbeid har bestått i å trinnvis forbedre denne første utgaven av søkemaskinen. Rapporten beskriver de programutvidr, datastrukturer og tester som vi har foretatt for hver utgave av søkeprogrammet. Takk til Stephen Alstrup for god veiledning underveis i prosjektet. Tor Jarle Sagen Stig Runar Vangen Steinkjer, 20 November 2003

Innholdsfortegn INNLEDNING...5 INNDATA (INPUT)...5 BESKRIVELSE AV DATASTRUKTURER BENYTTET I PROGRAMMET...6 LENKET LISTE...6 HASHTABELL...7 GJENNOMGANG AV SEARCHCMD 1...8 UTDATA (OUTPUT)...8 DATASTRUKTUR...8 OPPBYGGING AV DATASTRUKTUREN...9 HVORDAN SØK UTFØRES...9 ANALYSE AV ALGORITME...10 Tid...10 Minneforbruk...10 GJENNOMGANG AV SEARCHCMD 2...11 UTDATA (OUTPUT)...11 PROGRAMUTVIDELSER...11 DATASTRUKTUR...11 HVORDAN SØK UTFØRES...11 ANALYSE AV ALGORITME...12 Tid...12 Minneforbruk...12 GJENNOMGANG AV SEARCHCMD 3...13 UTDATA (OUTPUT)...13 PROGRAMUTVIDELSER...13 DATASTRUKTUR...13 OPPBYGGING AV DATASTRUKTUR...14 HVORDAN SØK UTFØRES...15 ANALYSE AV ALGORITME...15 Tid...15 Minneforbruk...15 GJENNOMGANG AV SEARCHCMD 4...16 UTDATA(OUTPUT)...16 PROGRAMUTVIDELSER...16 DATASTRUKTUR...16 OPPBYGGING AV DATASTRUKTUR...17 HVORDAN SØK UTFØRES...17 HVORDAN VI FINNER HASHVERDIEN TIL ET ELEMENT...17 ANALYSE AV ALGORITME...18 Tid...18 Minneforbruk...18 TEST AV SEARCHCMD 1-4...19 TEORETISK DEL...19 EKSPERIMENTELL DEL...20 HVORDAN VI HAR TESTET...21

FORKLARING TIL RESULTATENE...21 FUNKSJONELL TEST (BLACK BOX)...22 STRUKTURELL TEST (WHITE BOX)...23 GJENNOMGANG AV SEARCHCMD 5...25 UTDATA(OUTPUT)...25 PROGRAMUTVIDELSER...25 DATASTRUKTUR...25 HVORDAN SØK UTFØRES...26 OPPBYGGING AV DATASTRUKTUR...26 Tabellfordobling og rehashing av hashtabell...26 Rehashing...27 Fordobling av url-tabeller...27 ANALYSE AV ALGORITME...28 Tid...28 Minneforbruk...28 GJENNOMGANG AV SEARCHCMD6...29 UTDATA (OUTPUT)...29 PROGRAMUTVIDELSER...29 HVORDAN SØK UTFØRES...29 GYLDIGE SØKETEKSTER...30 TRESTRUKTUR FOR SØKEUTTRYKK...32 PARSERENS VIRKEMÅTE...33 BOOLSKE OPERASJONER...34 BOOLSK AND-OPERASJON...35 BOOLSK XOR-OPERASJON (EKSKLUSIV OR)...35 BOOLSK OR-OPERASJON...36 BOOLSK NOT-OPERASJON...36 KOMPLEKSE BOOLSKE OPERASJONER...37 ANALYSE AV ALGORITME...38 Tid...38 Minneforbruk...38 GJENNOMGANG AV SEARCHCMD7...39 GJENNOMGANG AV SEARCHSERVLET...40 UTDATA (OUTPUT)...40 PROGRAMBESKRIVELSE...41 GJENNOMGANG AV CRAWLER...43 DATASTRUKTUR...44 PROBLEMER VED DATASTRUKTUREN...44 KONKLUSJON...47 LITTERATURLISTE...48 VEDLEGG...49

Innledning SearchCmd er et program som implementerer en søkemotor i Java. Programmets hovedfunksjon er å søke etter forekomster av ord oppgitt av en bruker. Ved programmets oppstart leses en datafil inn, og en datastruktur opprettes derifra. Brukeren skriver inn et vilkårlig ord og programmet gir tilbakemelding hvis ordet eksisterer i datastrukturen. Tilbakemeldingen programmet gir og hvordan søket gjennomføres varierer fra de forskjellige utgavene av søkemaskinen. Tekstfilene som skal gjennomsøkes varierer i størr som beskrevet sener. Målet med SearchCmd er at søkemaskinen skal bli bedre for hver utgave. Med dette menes hastighet, minneforbruk og funksjonalitet. Inndata (Input) Programmets datafiler er de samme for alle utgavene av SearchCmd, og vil derfor kun bli beskrevet i rapportens første del. Brukerens søketekster og valgmuligheter vil variere noe, og vil bli beskrevet i detalj senere i rapporten. Utdata (Output) vil også variere, og vil derfor bli omtalt under hver gjennomgang av de ulike utgavene av SearchCmd. Programmets inndata består av en tekstfil og en tekststreng oppgitt av en bruker. Tekstfilen leses inn kun ved programmets oppstart, mens søketeksten kan oppgis flere ganger underveis i programmets gang. Tanken er at tekstfilen skal simulere en serie nettsider for bruk sammen med programmet. Tekstfilen består av url-er og tilhørende ord. En url er i denne sammenheng en linje i tekstfilen som begynner med *PAGE og etterfølges av en adresse til en nettside. Mellom hver url listes de ord som finnes på denne adressen. Tekstfilen har kun et ord per linje. Nedenfor vises de syv første linjene i tekstfilen.!" Det finnes tre tekstfiler av ulik størr for bruk sammen med SearchCmd. De tre filen er henholdsvis: Itcwww-small.txt (30.000 bytes) Itcwww-medium.txt (1.500.000 bytes) Itcwww-big.txt (20.000.000 bytes) 5

For at programmet skal fungere som forventet, er det noen krav til tekstfilen. En nettside må alltid identifiseres ved prefikset *PAGE. Det kan kun være et ord per linje i filen uten blanke tegn som f.eks. mellomrom. Det kan ikke være tomme linjer i tekstfilen. Første linje i datafilen må inneholde en nettside. Ord kan bestå av vilkårlige tegn. Ord kan ikke starte med prefikset *. Ordet vil da bli identifisert som en nettside. Tekstfilen kan være tom, men i så tilfelle vil vi heller ikke få treff på våre søk. Tekstfilen blir kun lest inn en gang. Det skjer ved at den overføres som et parameter til programmet ved oppstart for SearchCmd1-6. De resterende utgavene finner ut hvilke tekstfiler som eksisterer og lar brukeren velge datafil ut fra disse. Som nevnt består programmets inndata også av en tekststreng oppgitt av bruker. Bruker vil da typisk få oppgitt en ledetekst lydende Søk etter:, for derav å ha mulighet til å skrive inn et ord. Dette ordet vil så bli brukt i søkeprosessen. Beskriv av datastrukturer benyttet i programmet En datastruktur er en samling data som er samlet under ett navn. En datastruktur har som oppgave å knytte beslektede emner sammen på en effektiv og hensiktsmessig måte. I SearchCmd blir det benyttet flere ulike former for datastrukturer. I versjon 1, 2 og 3 blir det brukt en eller flere lenkede lister, mens versjon 4 benytter en hashtabell i kombinasjon med en lenket liste, såkalt chained hashing. I utgave 5 prøver vi i tillegg å spare plass, og bruker derfor tabeller i stedet for de fleste av listene. Lenket liste En liste er en ordnet sekvens av dataelementer. Lengden på listen er lik antall elementer i listen. Begynnn på listen kalles head, slutten på lista kalles tail. I en lenket liste lagres data i noder. En node er et objekt med en referanse til det neste objektet i tillegg til sine egne data. Det siste elementet i listen inneholder en null peker som indikerer at dette er slutten på listen. Hver gang et nytt element blir lagt til listen, blir noden tildelt minne dynamisk. Dette medfører at størrn på listen bare er begrenset av hvor mye minne som er tilgjengelig. (Weiss, 1999, s.433) start Per Kari Ola Leif.. null Referanse til Node Figur 1 - Prinsippskisse av lenket liste 6

Hashtabell Hashing er en metode for innsetting av data i en tabell. Dette gir oss fordeler som raskere innsetting og uthenting av data. Dette fordi den lenkede listen deles opp i mindre deler. (Se Figur 5 - Datastruktur SearchCmd4) Ved hashing brukes en nøkkelverdi for innsetting og søking av elementer i tabellen. Når man hasher verdier til en hash-tabell så gjøres dette ved hjelp av en hash-funksjon som bestemmer hvor i tabellen elementet som ønskes lagret skal plasseres. Hvert element genererer en verdi som bestandig er lik for tilsvarende objekter. Plasseringen for hvert objekt er tilfeldig, noe som gir jevn fordeling på hvor elementet plasseres i tabellen. (Weiss, 1999, s.553) Hashing har noen bakdeler. Hashing er basert på tabeller, og tabeller kan være vanskelig å utvide etter at de er laget. For enkelte typer hash-tabeller (f.eks. chained hashing), så vil ytn ha en drastisk nedgang når tabellen inneholder for mange elementer. Man må da enten ha en god innsikt i hvor stor tabellen må være, eller foreta en rehashing hver gang tabellen blir overfylt av data. 7

Gjennomgang av SearchCmd 1 Utdata (Output) Utdata til denne første utgaven av programmet er meget enkel. Det er kun en tekststreng som forteller om et ord eksisterer i tekstfilen eller ikke. Hvis brukeren for eksempel oppgir ordet skole, vil programmets utdata være : eventuelt #$ #$. Dette er utdata på sin mest primitive form. Programmet skiller ikke mellom url-er og ord. Brukeren vil ikke bli fortalt om et ord finnes flere ganger, eller hvilken url ordet finnes på. Datastruktur Programmet leser ved oppstart hver linje i tekstfilen og generer en lenket liste der hver linje i tekstfilen tilsvarer et objekt i den lenkede listen. Linje 1 Linje 2 Linje 3 Linje 4 null start Figur 2 - Datastruktur SearchCmd1 current Start peker alltid på første element, mens current peker på siste. For hvert nytt objekt oppdateres referansen i current objektet. Current referansen oppdateres til å peke på siste node i lista. 8

Oppbygging av datastrukturen Oppbyggingen av datastrukturen skjer på følgende måte: 1. Første linje i tekstfilen leses av programmet. 2. Dersom filen er tom avsluttes innlesningen. 3. Den første noden i det som skal bli vår lenkede liste opprettes. En referanse ved navn start blir satt til å peke på det første elementet. Dette er inngangen til lista vår, og vil bli brukt når vi senere skal behandle listen. 4. Programmet går inn i en løkke og en ny linje fra tekstfilen leses. Punkt 4 og 5 gjentas helt til tekstfilen er slutt og alle linjene er lest. Current-pekeren vil alltid peke til det siste elementet i listen. 5. En ny node opprettes. 6. Den nye noden knyttes så sammen med siste node. 7. Programmet datastruktur er nå ferdig oppbygd og klar til å bli benyttet av andre deler av programmet. Hvordan søk utføres Vi itererer gjennom listen ved å starte fra elementet angitt i start-variabelen. Søket blir avsluttet i det øyeblikk man finner ordet man leter etter eller dersom man kommer til det siste element. Programmet forteller så om ordet finnes eller ikke. 9

Analyse av algoritme For å analysere algoritmene bruker vi Big-Oh notasjon. Big-Oh beskriver vekstraten til en algoritme, det vil si antall operasjoner som kreves for å oppnå et resultat. N = Antall elementer / linjer i inndata-filen M = Allokering av minne Tid Oppbygging av datastruktur: O(N * M) Dette er en lineær algoritme hvor tid er direkte proporsjonal med mengden inndata. Dette stemmer bare dersom ord er av konstant lengde. Et kort ord som f.eks. hei vil ta kortere tid å prosessere enn lengre ord. Vi opererer ut fra gjennomsnittet, og uttrykket vil likevel stemme. For hvert nytt ord vil også noe tid bli brukt på å allokere minne til ord-objektet. Søk mislykket: O(N) Et mislykket søk vil kreve at vi undersøker alle noder i listen. Søk vellykket: O(N) I verste fall vil også et vellykket søk kreve at vi undersøker alle noder i listen. Tiden et søk tar er avhengig av hvor i listen den første instansen av ordet eksisterer. Dersom ordet finnes tidlig i filen, tar søket liten tid. Ord som finnes flere ganger vil vanligvis ta kort tid, da ordet mest sannsynlig vil befinne seg tidlig i datafilen. Til tross for dette, vil likevel Big-Oh bli det samme, da konstanter ikke er en faktor i denne notasjonen. Minneforbruk O(N) For hver linje i tekstfilen opprettes et nytt objekt. Vi kan derfor si at minneforbruket er direkte proporsjonalt med antall linjer i filen. 10

Gjennomgang av SearchCmd 2 Utdata (Output) Programmet skriver ut om et ordet finnes eller ikke. I tillegg blir alle url-er hvor det aktuelle ordet finnes skrevet til skjermen. Hver url skrives ut kun en gang, men med en teller som sier hvor mange ganger ordet finnes på url-en i en parentes. Et søk etter ordet it kan da for eksempel gi følgende resultat: %&' %(' )!&* Programutvidr Liste ut alle linker for et gitt søkeord. Datastruktur Det er ingen forandringer i datastrukturen fra SearchCmd 1. Oppbyggingen av datastrukturen foregår nøyaktig på samme måte. Hvordan søk utføres Vi starter fra første element og itererer gjennom hele listen. Alle url-er som inneholder det søkeordet man har angitt blir listet ut med antall treff internt i hver side. Dette har vi løst ved å mellomlagre url-er i en variabel. Hver gang et ord finnes på en url oppdateres en teller som forteller oss hvor mange ganger ordet finnes på url-en. Når vi da i den lenkede listen kommer til neste url, skrives foregående url som inneholdt søkeordet ut til skjerm, sammen med antall ganger søkeordet finnes på url-en. Dette fungerer korrekt pga. filens oppbygning. Filen starter alltid med en url som etterfølges av de ordene som finnes på url-en. I tillegg er det kun en forekomst av hver unike url i filen. Dette i henhold til kravene til tekstfilen. 11

Analyse av algoritme Det er ingen endring i tid for oppbygning av datastruktur og minneforbruk fra forrige versjon. Derimot er det en økning i tidsforbruk for søk. N = Antall elementer / linjer i inndata-filen M = Allokering av minne Tid Oppbygging av datastruktur: O(N * M) Dette er en lineær algoritme hvor tid er direkte proporsjonal med mengden inndata. Søk: O(N) Et søk i SearchCmd 2 vil ta like lang tid uansett om søket er vellykket eller ikke. Dette fordi det blir søkt i hele listen for å finne ut hvilke url-er som ordet finnes på. Minneforbruk O(N) For hver linje i tekstfilen opprettes et nytt objekt. Vi kan derfor si at minneforbruket er direkte proporsjonalt med antall linjer i filen. 12

Gjennomgang av SearchCmd 3 Utdata (Output) Utdata er nesten identisk med SearchCmd 2. I tillegg til å telle antall url-er, summerer også denne utgaven antall treff internt i sidene. %&' %(' $+,!,"&%' Programutvidr Datastrukturen skal kun inneholde unike ord. Hvert ord skal knyttes opp mot en eller flere url-er, der hver url forekommer kun ett sted i minnet. Datastruktur Datastrukturen i SearchCmd 3 er noe forskjellig fra de foregående utgavene av programmet. I stedet for å benytte kun en lenket liste, vil vi nå opprette flere lister. En av disse listene inneholder kun ord, med hvert unike ord kun en gang. Hver ord-node inneholder en referanse til en liste som består av noder med de url-ene som ordet finnes på. Hver url er unik innenfor hvert ord, mens hver url kan høre til ett eller flere ord. *Page 2 Ord 1 Link 1 Link 2 *Page 3 Ord 2 Link 3 *Page 1 Ord 3 Link 4 Link 5 *Page 4 Ord 4 Link 6 Link 7 Link 8 Figur 3 - Datastruktur SearchCmd3 *Page 5 *Page 6 13

Oppbygging av datastruktur Oppbyggingen av datastrukturen i SearchCmd 3 er noe mer avansert enn i foregående utgaver av programmet. Oppbyggingen av datastrukturen starter med at en linje fra tekstfilen leses inn, for så å sjekke om den innleste linjen er en url eller et ord (A). Hvis det er en url, mellomlagres url en i en variabel (B) og programmet leser neste linje i tekstfilen. Hvis den innleste linjen er et ord blir det først kontrollert om ordet finnes i lista fra før (C). Utfallet av denne kontrollen avgjør programmets videre gang. Finnes ordet i lista fra før, sjekkes det om det eksisterende ordet er knyttet opp mot den aktive url en (E). Er eksisterende ord knyttet opp mot url leses neste linje i tekstfilen (F). Hvis ikke knyttes url en opp mot eksisterende ord (G). Finnes ikke ordet vi sjekker i lista fra før, legges ordet til og knyttes samtidig opp mot url en ordet befinner seg på (D). Oppbygningen av datastrukturen skjer ved at hvert gjennomløp starter i A, og slutter i enten B, D, F eller G. Dette er forsøkt forklar nedenfor. start A B C D E F G Figur 4 Oppbygging av datastruktur SearchCmd3 A. Les inn en ny linje. Er innleste element en url? Ja B, Nei C B. url mellomlagres i en variabel link. Avslutt C. Finnes elementet i ordlisten? Ja E, Nei D D. Opprett nytt ordelement som legges til på slutten av listen med et nytt urlelement. Avslutt E. Kontroller om url allerede eksisterer. Ja F, Nei G F. Avslutt G. Opprett nytt url-element. Avslutt 14

Hvordan søk utføres En referanse til første node i den lenkede listen finnes i variabelen start. Vi itererer gjennom listen til vi treffer på søkeordet. Alle linker tilhørende dette ordet blir så listet ut. Dersom ordet ikke eksisterer i listen vil en informativ tekst om dette bli skrevet ut. Analyse av algoritme N = Antall elementer / linjer i inndata-filen M = Allokering av minne K = Antall unike ord U = Antall unike linker L = Antall linker per ord i gjennomsnitt Tid Oppbygging av datastruktur: O(N * K + K * M) For hver linje i tekstfilen som leses inn kontrollerer vi om dette ordet allerede eksisterer i minnet. Vi kan da si at datastrukturen blir av K lengde og kontrolleres N ganger. Søk: O(K) Et mislykket søk vil føre til at vi søker gjennom hele datastrukturen som er K lang. Et vellykket søk vil ta kortere tid enn et mislykket søk da man ikke trenger å iterere gjennom hele listen. Minneforbruk O(K + U + K * L) For hvert unike ord opprettes det et nytt objekt. I tillegg er hver url et eget objekt. For å linke ord med url-er har vi i tillegg noen objekter som binder ord og url-er sammen. 15

Gjennomgang av SearchCmd 4 Utdata(output) Utdata er nesten identisk med SearchCmd 3. Det summeres ikke hvor mange ganger ordet forekommer, men antall interne linker for hver side blir summert. %&' %(' Programutvidr Erstatt den lenkede listen med en hashtabell datastruktur (chained hashing) Datastruktur Vår datastruktur for SearchCmd 4 baserer seg på en hash-tabell. Fra hver indeks i hashtabellen har vi en datastruktur som er identisk med SearchCmd 3. Den lenkede listen fra den forrige oppgaven er delt opp i mindre biter der hver lenkede liste har sitt utspring fra tabellen. it aktuelt 2 7 Indeks 0 Ord 1 Ord 2 *Page 1 Indeks 1 Link 1 Link 3 *Page 2 Indeks 2 Indeks 3 Link 2 *Page 3 Indeks 4 Indeks 5 Indeks 6 Indeks 7 Ord 3 Ord 2 Ord 4 Link 4 Link 5 *Page 4 *Page 5 Figur 5 - Datastruktur SearchCmd4 16

Oppbygging av datastruktur Vi har på forhånd bestemt oss for hvilken tabellstørr vi vil bruke. Vi genererer en tabell med størr på 50.000 elementer. Deretter har vi en hash-funksjon som behandler en tekststreng, og returnerer hvilken indeks i tabellen denne teksten skal plasseres under. Å fastsette størrn for hash-tabellen på forhånd kan være uheldig. Ved en for stor tabell vil vi oppleve stor spredning av elementene og høyt minneforbruk. Med en liten tabell får vi liten spredning og høyt tidsforbruk grunnet flere elementer i hver liste. A SC3 SC3 SC3 SC3 Figur 6 - Prinsipiell skisse av SearchCmd4 I A finner vi hash-verdien for tekst-strengen. Ut fra denne verdien finner vi ut hvilket tabellelement vi skal plassere ordet under. Alle disse tabellelementene fungerer selvstendig som en utgave av SearchCmd3. Hvordan søk utføres Vi beregner en hash-verdi ut fra søkeordet. Korrekt lenket liste velges fra denne verdien, og det korrekte ordet blir funnet på samme måte som i SC3. Hvordan vi finner hashverdien til et element Prosessen med å tilegne en hashverdi til et element kalles hashing. Når en tekststreng i SearchCmd 4 skal tilegnes en hashverdi utføres det et metodekall til metoden hashcode. public static int calchash(string word) return Math.abs(word.hashCode() % hashsize); Figur 7 calchash metodedefinisjon 17

Parameter til metoden er tekststrengen som skal tilegnes en hashverdi. Deretter kalles metoden hashcode i java.lang.string opp på vegne av tekststrengen. HashCode returnerer et heltall (int) kalkulert ut fra følgende matematiske kode: Denne formelen er hentet ut fra dokumentasjonen til Java. Vi må så sørge for at det returnerte heltallet befinner seg i område [0 tabellstørr - 1]. Det skjer ved å bruke mod (%) funksjonen. Returnerte heltall mod tabellstørr, vil for eksempel når tabellstørreelen er [10] returnere et tall mellom 0 og 9. Nærmere bestemt vil heltallet 32 få verdien 2 når tabellstørrn er 10. 10 x 3 = 30 som gir en rest på 2. Tekststrengen plasseres da i hashtabellens index nr [2]. Analyse av algoritme N = Antall elementer / linjer i inndata-filen M = Allokering av minne K = Antall unike ord L = Antall linker per ord T = Størr hashtabell Tid Oppbygging av datastruktur: O(T * M + N * [K / T]) For hver linje i tekstfilen som leses inn kontrollerer vi om dette ordet allerede eksisterer i minnet. Kontrolltiden er avhengig av hvor lang hver lenkede liste i tabellen er. I tillegg vil vi forbruke tid ved opprettingen av tabellen. Søk: O(K / T + L) Et søk vil iterere gjennom hele den lenkede listen som tilhører hashverdien av søkeordet inntil søkeordet er funnet. Deretter itereres alle url-er, slik at disse kan returneres til brukeren. Mislykkede søk: O(K / T) Et søk vil iterere gjennom hele den lenkede listen som tilhører hashverdien av søkeordet. Minneforbruk O(T + K + U + K * L) For hver unike ord lages et nytt objekt. I tillegg har hver url sitt eget objekt. For å linke ord med url-er har vi i tillegg noen objekter som binder ord og url-er sammen. 18

Test av SearchCmd 1-4 Teoretisk del N = Antall elementer / linjer i inndata-filen M = Allokering av minne K = Antall unike ord U = Antall unike linker L = Antall linker per ord T = Tabell størr (hash) SC1 SC2 SC3 SC4 Innlasting av fil O(N * M) O(N * M) O(N * K + K * M) O(T * M + N * [K / T]) Søk mislykket O(N) O(N) O(K + L) O(K / T + L) Søk vellykket O(N) O(N) O(K) O(K / T) Minneforbruk O(N) O(N) O(K + U + K * L) O(T + K + U + K * L) Figur 8 - Oppsummering av teoretisk tids- og minne-forbruk Tidsforbruket ved innlasting av fil for de to første versjonene er lineært avhengig av antall linjer i datafilen. For hver linje er det nødvendig å opprette et nytt objekt i minnet. I tillegg til at selve innlesningen tar tid, krever også minneallokeringen litt tid. For utgave 3 ser vi at minneallokering kun skjer for hvert unike ord. K vil alltid være mindre enn N, da hvert ord mest sannsynlig forekommer flere ganger fra datafilen. Likevel må alle ord mottatt fra datafilen kontrolleres mot alle registrerte ord. Denne utgaven vil bli mer minneeffektiv enn de to tidligere, men den vil også bli den absolutt tregeste. For utgave 4 ser vi at antall kontroller om ordet allerede eksisterer divideres med størrn på hash-tabellen (K/T). Dette medfører en dramatisk forbedring i tidsforbruket, særlig på større datafiler. Et søk vil lete gjennom alle elementer mottatt fra datafilen i de to første utgavene. Utgave 3 søker kun gjennom alle unike ord. Dersom ordet eksisterer, itereres også listen med ordets urler. For utgave 4 skjer det samme, bortsett fra at tabellen hjelper oss med å finne korrekt ord med mindre jobb. Hashtabellen leder oss til en mindre liste i stedet for å lete gjennom en stor liste med alle ord (K/T). Minneforbruket for de to første utgavene er lineært avhengig av antall linjer i datafilen. For hver linje i datafilen opprettes et nytt objekt i minnet. I utgave 3 prøver vi å fjerne redundans ved å opprette kun ett nytt objekt for hvert unike ord (K). I tillegg har vi kun ett objekt for hver unike url (U). For å binde ord sammen med url-er benytter vi enda et objekt (K * L). Med utgave 4 vil vi bruke litt mer minne pga. at vi oppretter en hashtabell med fast størr for å minimere tidsforbruket ved opprettn og søk i datastrukturen. Med utgave 5 ønsker vi å bruke en dynamisk størr på hash-tabellen, og tabeller for å lagre unike url-er og sammenknytningen mellom ord og url-er. 19

Eksperimentell del I den eksperimentelle delen av testen er målet å få frem tall som sier noe fornuftig om de ulike utgavene av SearchCmd. Vi vil teste på følgende punkter: Oppbygning av datastruktur Søk (gjennomsnittstid på x antall ord som finnes i datastrukturen) Søk etter ord som ikke finnes (søker gjennomhele datastrukturen) Minnebruk Oppbygging av datastruktur Small Medium Big SearchCmd1 61 ms 2033 ms Out of memory SearchCmd2 60 ms 2023 ms Out of memory SearchCmd3 211 ms 749217 ms Out of time SearchCmd4 85 ms 1400 ms 14250 ms Søk etter ord som finnes Small Medium Big SearchCmd1 0.3434 ms 37.07 ms Out of memory SearchCmd2 1.5505 ms 109.723 ms Out of memory SearchCmd3 0.0311 ms 4.765 ms Out of time SearchCmd4 0.00022 0.00037 ms 0.191 ms Søk etter ord som ikke finnes Small Medium Big SearchCmd1 0.6 ms 85.569 ms Out of memory SearchCmd2 1.402 ms 119.157 ms Out of memory SearchCmd3 0.08 ms 7.01 ms Out of time SearchCmd4 0.00001 ms 0.00001 ms 0.00005 ms Minneforbruk Small Medium Big SearchCmd1 5.552 kb 19.332 kb Out of memory SearchCmd2 5.696 kb 19.328 kb Out of memory SearchCmd3 5.416 kb 9.192 kb Out of time SearchCmd4 7.176 kb 9.448 kb 34.408kb Figur 9 - Måling av tid og minneforbruk 20

Hvordan vi har testet Søk etter ord i datastrukturen vil ofte ta så kort tid at resultatet vil bli 0.0 ms. Vi har derfor valgt å legge søket inn i en løkke, slik at søket utføres 1000 ganger for SC1, 2 og 3. For SC 4 utføres søket 100 000 ganger. Ved så å dele sluttresultatet på antall ganger løkka har iterert vil vi da få det teoretiske antall millisekund som søket tar. Når det gjelder minne, har vi testet hvor mye minne programmet opptar ved å lese av hvor mye minne prosessen bruker fra Oppgavebehandling (Task Manager). Herifra finner vi prosessen java.exe og ser hvilket plassforbruk denne prosessen innehar. Forklaring til resultatene Datastruktur: Resultatet for oppbygningen av datastrukturen er så å si identisk for SC1 og SC2, både for tekstfilen small og medium. Dette stemmer bra med teorien, da dette er en lineær funksjon O(N) hvor tidsforbruket er direkte proporsjonal med mengden inndata. Det lar seg ikke gjøre å bygge opp datastrukturen for tekstfilen big med SC1 og SC2 pga minneforbruket blir for høyt. For SC3 er det en betydelig økning i tid sammenlignet med de to forrige utgavene. Dette skyldes at denne utgaven har en del operasjoner som er tidkrevende. Som det går frem av tabellene har SC3 en voldsom økning i tidsforbruket fra small til medium. SC4 benytter en hashtabell i kombinasjon med mange små lenkete lister. I teorien er innsetting av data i en hashtabell raskere en lenkede lister. Som vi ser så får ikke dette utslag når mengden inndata er liten. Når mengden inndata øker er datastrukturen i SC4 overlegen de andre. SC4 er den eneste utgaven som fungerer effektivt for tekstfilen big. SC3 vil klare å lese inn tekstfilen big, men det vil ta urimelig lang tid. Søk: SC1 vil i gjennomsnitt finne søkeordet etter å ha iterert gjennom halve datastrukturen. Dette stemmer bra med våre resultater da det er en dobling i benyttet tid for søk etter ord som ikke finnes. SC2 har en identisk datastruktur men likevel en betydelig økning i tidsforbruket. Dette skyldes at SC2 alltid må søke gjennom hele datastrukturen for å liste opp url er som ordet finnes på. Som vi ser vil da et søk som gir treff og et som ikke gir treff ta tilnærmet lik tid. SC2 har en veldig ineffektiv søkemetode. Dette resulterer i høyere tidsforbruk både for alle typer søk SC3 skal i teorien utføre søket raskere da datastrukturen som skal gjennomsøkes er mindre (kun unike ord). SC4 utfører søk raskere enn sine forgjengere. Dette skyldes måten datastrukturen er oppbygd på (mange korte lister ut fra hver tabellelement). Minne: For den minste datafilen ser vi at de første tre utgavene bruker omtrentlig like mye minne. Vi antar at grunnen til økningen i minneforbruk for utgave 4 grunnes den mer komplekse datastrukturen som ikke kommer til sin rett for mindre datafiler. Når vi da kikker på den medium store filen ser vi at minneforbruket for utgave 3 og 4 er omtrentlig det samme og halvparten av de to første. Dette kan tyde på at vår datastruktur er mer effektiv for større datamengder. For den største datafilen er det kun utgave 4 og utover som har mulighet til å lese inn datafilen. Vi kan se at selv om datafilen er 13 ganger større enn den forrige, bruker vi bare litt over 3 ganger så mye minne. Dette antas å være på grunn av at flere ord gjentas og at man da ikke trenger å gjenta ordet på nytt. 21

Funksjonell test (black box) Funksjonalitetstesting er en teknikk for software testing, hvor testeren ikke kjenner til de indre mekanismene til de elementer som skal testes. For eksempel ved en black box test av et software design vil testeren kun ha kjennskap til hva som blir skrevet inn (input) og hva det forventede resultatet skal bli (output). Hvordan programmet kommer fram til resultatet forblir ukjent. Testeren ser aldri på koden til programmet og behøver heller ikke mer inngående kjennskap til programmet enn de oppgitte spesifikasjoner. X = Vi fikk det resultatet vi i utgangspunktet forventet å få Input Resultat som vi fikk Forventet Søk på ord som inneholder å, ø, æ Beskjed om at ordet ikke finnes for X kommandolinje-utgavene, treff for GUIog servlet-utgaven Søk på ord med få bokstaver (i) Fungerer på samme måte som andre ord X Søk på lange ord Fungerer på samme måte som andre ord X Ingen søking, søkeord er tomt Programmet vil avsluttes X Tekstfil som kun innholder ord NullPointerException Tekstfil som inneholder tom linje, Programmet vil ikke kjøre først eller midt i fila Tekstfil som er tom Ingen treff X Start programmet uten parametere Bruker vil få melding om hvordan X programmet skal startes for SC4 og senere Angi filnavn som ikke finnes FileNotFoundException X Figur 10 Black box betingr 22

Strukturell test (white box) En strukturell test er en teknikk for software testing hvor kjennskap til hvordan de indre mekanismene fungerer er nødvendig. Denne kunnskapen blir brukt til å velge test data. I motsetning til black box testing, vil man ved white box testing spesifikt bruke de kunnskaper man har om programkoden til å undersøke output. Nøyaktigheten til denne testen avgjøres av om testeren vet hva programmet er ment å gjøre. Han eller hun kan da se om programmet avviker fra forventet oppførsel. public static void search(word[] l, String word) int step1 = 0; int step2 = 0; int step3 = 0; int step4 = 0; System.out.println("search, start"); word = word.tolowercase(); int pos = calchash(word); Word curr = l[pos]; Word start = curr; curr = start; System.out.println("search, step 1: " + (++step1)); while (curr!= null) /*Valg 1*/ System.out.println("search, step 2: " + (++step2)); if (curr.str.equals(word)) /*Valg 2*/ System.out.println("search, step 3: " + (++step3)); curr.printlinks(word); break; curr = curr.next; System.out.println("search, step 4: " + (++step4)); if(curr == null) /*Valg 3*/ System.out.println(word + " finnes ikke i lista"); Figur 11 Søkemetoden for SearchCmd4 Vi valgte søkefunksjonen for SC4 for vår strukturelle test. Enkelt forklart så utfører denne funksjonen et søk i datastrukturen etter oppgitt søkeord fra bruker. 23

Valg Datasett Egenskaper for datasett 1 Ingen ganger A Tom ordliste 1 En gang B Ordliste med et ord 1 Flere ganger C Ordliste med flere ord, ordet eksisterer 2 True C Ordet eksiterer 2 False B Ordet eksisterer ikke 3 True A, B Ordet eksisterer ikke 3 False C Ordet eksisterer Figur 12 White box betingr Tabellen viser alle mulige tilstander kodebiten vår kan ha. Datasett Ordliste Søkeord Utdata Step1 Step2 Step3 Step4 A Tom ordliste It Ingen treff 1 0 0 1 B Aktuelt It Ingen treff 1 0 0 1 C Aktuelt,It It It 1 1 1 1 Figur 13 White box teoretisk Ved hjelp av tre datasett kan vi teste alle de tilstander vår kode kan ha. Da våre datasett er relativt små, er det lett for oss å vite akkurat det forventede resultat. Fra vår test kan vi se at alle deler av metoden ble besøkt ved vellykkede søk. Vi kan da si at denne metoden fungerer som forventet. Datasett A: En helt tom tekstfil. Datasett B: -**(! Datasett C: -**(! 24

Gjennomgang av SearchCmd 5 Utdata(output) Utdata er identisk med SearchCmd 4. Programutvidr Mindre minneforbruk Hashtabell som utvider seg etter behov (rehashing) En egen tabell som inneholder alle url-er Lenket liste med url-er fra hvert ord erstattet med en tabell Datastruktur SC5 lagrer unike ord i en hashtabell etter samme prinsipp som SC4 (se Figur 5 - Datastruktur SearchCmd4). Alle url-er legges inn i en egen urltabell. Første url i tekstfilen legges inn i tabellindex[0], den neste i index[1] osv. I SC4 inneholdt hvert unike ord en egen liste som bestod av referanser til hver enkelt url som ordet fantes på. Denne listen er nå erstattet med en urltabell. Hver ordobjekt har nå sin egen index-tabell. Denne tabellen inneholder tall som samsvarer med tabellindex i tabellen med url-er. Hashtabell 0 Ordobjekter URL indextabell Hans 0 0 Urltabell *PAGE:Itc 1 2 2 1 2 *PAGE: *PAGE: 3 4 3 *PAGE: 4 5 4 *PAGE: 5 5 *PAGE: 6 7 Grete 5 8 6 *PAGE: 7 *PAGE: 8 *PAGE: Figur 14 - Datastruktur SearchCmd5 9 *PAGE: 25

Hvordan søk utføres Søk utføres likedan som i SearchCmd4. Når man da finner ordet, brukes url-tabellen for ordet til å hente ut alle url-er i url-listen. Oppbygging av datastruktur Datastrukturen for unike ord i SC4 bestod av en hashtabell med fast størr. Dette er meget upraktisk da vi på forhånd ikke kan vite hvor mange ord det er som skal inn i datastrukturen. Datastrukturen i SC5 består av tabeller som i utgangspunktet er satt til tabellstørr 1. Vi bruker så prinsippet med fordobling av tabeller når innholdet overskrider størrn på tabellen. Tabellfordobling og rehashing av hashtabell Fordobling av tabellstørrn under oppbygning av datastrukturen gir oss muligheten til å dynamisk sette størrn på tabellene underveis i programutførn. En tabellstørr for hash-tabellen større enn antall elementer gir høyere yt enn en tabell mindre enn antallet unike ord. For vanlige tabeller er vi tvunget til å bruke en større tabell uansett for å kunne indeksere våre data. Som vist i figuren under vil en tabell med størr [8] fordobles til størr[16], etter at det niende unike ordet er satt inn i tabellen. Antall elementer Tabellstørr 1 1 2 2 3 4 5 8 9 16 Figur 15 - Resizing av hash-tabell 26

Rehashing Når hashtabellen dobles i størr må alle elementene (unike ord) flyttes over til den nye tabellen. Denne prosessen kalles re-hashing. Hver enkelt ord-objekt må få en ny hashverdi og flyttes til tilsvarende plass i den nye tabellen. Dette skjer i metoden resizewordtable. public static void resizewordtable() //Setter ny størrn på tabellen Word[] newtable = new Word[wordTable.length*2]; // Travaserer gjennom listene i de ulike tabell indexene for (int i = 0; i < wordtable.length; i++) Word list = wordtable[i]; // list peker på første node i tabell index i while (list!= null) // Dette er neste node i lista. // Må huske den før vi forandrer verdien til list Word next = list.next; // Rehashing int hash = (Math.abs(list.str.hashCode())) % newtable.length; // Setter next verdien til noden før flytting list.next = newtable[hash]; // Flytter noden til NY tabell newtable[hash] = list; // Neste node i GAMMEL tabell list = next; // Erstatter den gamle tabellen med en ny wordtable = newtable; Figur 16 Rehashing av hashtabell Fordobling av url-tabeller Prinsippet med dobling brukes også på tabellen som inneholder alle url-ene som finnes i tekstfilen. Tabellene som inneholder indekser for hvilke url-er et ord finnes på bruker samme prinsipp. Startstørrn er satt til [1]. Tabellen dobles i størr når antall elementer i tabellen tilsvarer tabellstørrn. Det viktig å merke seg at her skjer doblingen på det tidspunktet når tabellstørrn er lik antall elementer, og ikke når antall elementer overstiger tabellstørrn slik som i hashtabellen. Dette er selvsagt fordi en vanlig tabell ikke kan inneholde flere elementer enn tabellstørrn. 27

Analyse av algoritme N = Antall elementer / linjer i inndata-filen K = Antall unike ord L = Antall linker per ord T = Størr hashtabell Tid Oppbygging av datastruktur: O(T * M + N * [K / T] * M) For hver linje i tekstfilen som leses inn kontrollerer vi om dette ordet allerede eksisterer i minnet. Kontrolltiden er avhengig av hvor lang hver lenkede liste i tabellen er. I tillegg vil vi forbruke tid ved opprettingen av tabellen. Prosessen for å legge til nye url-er for ordene vil ta omtrentlig like lang tid hver gang. Søk: O(K / T + L) Et søk vil iterere gjennom hele den lenkede listen som tilhører hashverdien av søkeordet inntil søkeordet er funnet. Deretter itereres alle url-er, slik at disse kan returneres til brukeren. Mislykkede søk: O(K / T) Et søk vil iterere gjennom hele den lenkede listen som tilhører hashverdien av søkeordet dersom ordet ikke eksisterer. Minneforbruk O(T + K + U + K * L) Vi bruker den samme notasjonen som i SC4, men i praksis vil minneforbruket bli noe redusert, da vi bruker en mer optimal datatype. En tabell har mindre overhead i forhold til en lenket liste, der hvert enkelt objekt har en egen overhead. 28

Gjennomgang av SearchCmd6 Utdata (Output) Denne utgaven av programmet lister ut alle linker der det angitte søkeuttrykket stemmer. Et søk etter it AND stillinger vil gi følgende utdata:./0,.$ &%' Da de komplekse boolske operasjonene parses av programmet, er det mulig å komme over en operasjon som ikke er korrekt formatert. Derfor er det i tillegg også mulig å få en feilmelding dersom brukeren skriver inn en operasjon som ikke er korrekt. -%%' 1,2, I dette tilfellet reagerer programmet på at man bruker feil antall parenteser. Man må ha like mange parentesstarter som parentesavslutninger. Programutvidr Boolske operasjoner Komplekse boolske søk (flere boolske operasjoner og parenteser) Fritekstsøk Hvordan søk utføres Hvert søk blir delt opp i mindre biter slik at boolske operasjoner kan utføres på de mindre bitene. Ved å analysere parentesene ser vi hvilke operasjoner som skal utføres mot hverandre. For de elementene som ikke er oppdelt med parenteser utføres sammenligningene fra venstre mot høyre. Det er en akseptert standard å behandle uttrykk fra venstre møt høyre, og vi bruker derfor denne metoden. Denne metodikken kalles for parsing. Metoden for parsing er rekursiv. Det vil si at metoden deler større problemer opp i mindre, og sender forespørsler om mindre og mindre operasjoner til seg selv. Svaret den kommer tilbake med er en liste med resultatet av underproblemet. Den ytterste metoden vil da ha det ferdig kalkulerte resultatet. Dette er en metode som kalles splitt-og-hersk på grunn av den måten vi deler større problemer opp i mindre, lettere oppgaver. Søk utføres på det laveste nivået. Når parseren har delt opp alt i de minste mulige elementene, står man igjen med et sett av ord. Ordene tolkes slik at de ordene som ikke er gjenkjent vil bli et vanlig ord. Disse ordene sendes så gjennom en metode tilsvarende de tidligere søkemetodene. Forskjellen denne gangen er at denne søkemetoden returnerer en liste med tall i stedet for å skrive ut alle resultater fortløpende. Resultatet av søket vil bli skrevet ut når alle operasjoner er gjennomført. 29

Gyldige søketekster Ved et søk sørger parseren for å dele opp et søkeuttrykk i mindre elementer. Etter utført parsing kjenner programmet til hva hvert element er, uten at man trenger å vite hva hvert element inneholder. Elementene kan i dette tilfellet være et ord, en parentes, et mellomrom eller et boolsk uttrykk. Et gyldig uttrykk kan beskrives ved hjelp av en notasjon ved navn Backus-Naur Form. BNF brukes for å beskrive kontekstfri grammatikk. Et gitt søkeuttrykk kan brytes ned i grunnelementer og regler for hvilke uttrykk som da er gyldige kan da beskrives. Hvert element beskrives ved hjelp av en klamme med elementtype. (Foldoc, 1997) 1 2 3 4 5 6 7 8 <resultat> ::= <uttrykk> <uttrykk> ::= <ord> <uttrykk> <operasjon> <uttrykk> <uttrykk> <uttrykk> <parentes1> <uttrykk> <parentes2> <operasjon> ::= AND OR XOR NOT <parentes1> ::= ( <parentes2> ::= ) Figur 17 Grammatikk for gyldige søk Backus-Naur Form Vi kan fra denne tabellen se at et resultat alltid er utledet av et uttrykk. Den enkleste formen av et uttrykk kan vi se at består av kun ett ord. Videre kan vi se at et uttrykk kan utledes av et uttrykk mot et annet uttrykk ved hjelp av en operasjon. To uttrykk mot hverandre uten en operasjon blir automatisk behandlet som en AND-operasjon. Et uttrykk inne i et sett med parenteser resulterer i nok et nytt uttrykk. Vårt program har totalt fire operasjoner, der alle har den samme verdien. Parentesene angis som standard parentestegn. (Hosking, 2000, s.90) 30

For å bevise dette settet med regler bruker vi nok et skjema. Vi tester grammatikken med søketeksten:,/0%!#3' Gramatikk nr. Setningsmessig form Inndata 1 <resultat> stillinger AND (aktuelt OR it) 4 <uttrykk> stillinger AND (aktuelt OR it) 5 <uttrykk> <uttrykk> stillinger AND (aktuelt OR it) 3 <uttrykk> <parentes1> <uttrykk> stillinger AND (aktuelt OR it) <parentes2> 2 <uttrykk> <parentes1> <uttrykk> stillinger AND (aktuelt OR it) <operasjon> <uttrykk> <parentes2> 2 <uttrykk> <parentes1> <uttrykk> stillinger AND ( aktuelt OR it) <operasjon> <ord> <parentes2> 3 <uttrykk> <parentes1> <ord> stillinger AND (aktuelt OR it) <operasjon> <ord> <parentes2> 2 <uttrykk> <operasjon> <parentes1> stillinger AND (aktuelt OR it) <ord> <operasjon> <ord> <parentes2> - <ord> <operasjon> <parentes1> <ord> <operasjon> <ord> <parentes2> stillinger AND (aktuelt OR it) Figur 18 Kontroll av grammatikk Backus-Naur Form Denne tabellen viser parsingen av den angitte søketeksten. Tabellen leses fra bunnen, der vi kan se hva den første operasjonen innebærer. I sin originale form ser vi alle elementer beskrevet som elementtyper. Pilene i teksten til høyre viser hvilket element som blir behandlet av grammatikkdelen angitt på venstre side. Antall elementer skal etter hvert kuttes ned, slik at vi til sist skal stå igjen med resultatet av søkeuttrykket. Dette gjøres ved hjelp av de grammatikkreglene vi tidligere har definert for vår parser. (Hosking, 2000, s.91) 31

Trestruktur for søkeuttrykk uttrykk AND ord stillinger parentes ( ) uttrykk OR ord aktuelt ord it Figur 19 Trestruktur for et søkeuttrykk I praksis vil parseren bygge opp en trestruktur i minnet ved hjelp av stakken, i og med at vi bruker en rekursiv metode. Med stakk i dette tilfellet menes den prosessen som skjer ved rekursive metodekall. For hver gang en metode kaller på seg selv vil en bit av minnet reserveres til å huske tilstanden til denne metoden frem til det nye metodekallet. Dersom vi ønsker, er det også mulig å ta vare på dette treet. Vi kunne brukt treet for å finne hvilke noder som skal tolkes først. Da alle våre operasjoner er av samme verdi, har vi ikke et behov for denne vektingen. Tolkeren opererer fra venstre mot høyre og behandler alle operasjoner ut fra denne rekkefølgen. Vi valgte denne løsningen både på grunn av at den er enkel, og fordi det er en industristandard. 32

Parserens virkemåte Stack Søkeuttrykk Skanner element Parser Resultat Søk mot datastruktur Figur 20 Prinsipiell virkemåte for parseren Et søkeuttrykk behandles gjennom flere steg. Det første steget består av en skanner som leser gjennom søkeuttrykket tegn for tegn fra venstre mot høyre. Underveis i skanningen leter denne delen opp eventuelle reserverte ord og forhåndsbestemte språkelementer. Alle ord som ikke faller i disse kategoriene behandles som et ord som det skal utføres et søk på. Fra parseren plasseres alle uttrykk inne i en parentes på stakken, og behandles deretter av en ny parser. Alle ord resulterer i et søk mot datastrukturen. Resultatet av dette søket tas vare på som en midlertidig tabell. (Aho, 1986, s.57) Ved et reservert ord sammenlignes to søkeresultater, og en ny midlertidig tabell med resultatet av denne sammenligningen tas vare på. Når da alle elementer er behandlet, står parseren igjen med kun én liste. Denne listen vil da være resultatet av søkeuttrykket. Dersom parseren kommer over en feil under parsingen av søkeuttrykket returneres en null-verdi i stedet for listen. I dette øyeblikket kan vi vite at søket var mislykket, og kan vise en feilmelding på grunnlag av dette. 33

Boolske operasjoner Alle metoder for boolske operasjoner mottar to tabeller som skal sammenlignes med tanke på den operasjonen de er tiltenkt. Ut fra denne tabellen genereres nok en ny tabell der alle elementer svarer til den boolske operasjonen man har valgt. Alle disse operasjonene opereres ved å behandle to tabeller og genererer en ny tabell med resultatet fra den boolske operasjonen. For at disse metodene skal kunne fungere normalt, kreves det at de tabellene som brukes som inndata for metodene er sortert i kronologisk rekkefølge. For at de komplekse boolske sammenligningene skal fungere, kreves det også at utdata er i korrekt rekkefølge. Peker 1 Peker 3 1 2 3 4 1 3 5 6 Peker 2 Figur 21 Bruk av tabeller ved boolske operasjoner Peker 1 og peker 2 refererer til hver av sine respektive tabeller. Peker 3 refererer her til resultat-tabellen som ble opprettet på forhånd. 34

Boolsk AND-operasjon Formålet med denne operasjonen er å finne alle elementer som finnes i begge lister. Ved metodens oppstart genereres en liste tilsvarende lengden på begge lister til sammen. To tellere settes til å peke på de første elementene i hver liste. Listene itereres til man har kikket gjennom begge listene. For hver iterasjon har man tre mulige utfall. 0 AND 0 = 0 0 AND 1 = 0 1 AND 0 = 0 1 AND 1 = 1 Figur 22 AND operasjon Elementer i liste 1 er mindre enn elementet i liste 2. Peker 1 flyttes til neste felt. Elementer i liste 1 er større enn elementet i liste 2. Peker 2 flyttes til neste felt. Elementer i liste 1 er lik elementet i liste 2. Elementet legges til i liste nummer 3. Peker 1, 2 og 3 flyttes til neste felt. Når en av pekerne når enden av listen omformes liste 3 til en liste med det totalt antall like elementer fra liste 1 og 2. Denne returneres så tilbake. Boolsk XOR-operasjon (eksklusiv OR) Denne operasjonen skal finne de elementer som finnes i kun en av listene. Ved metodens oppstart genereres en liste tilsvarende lengden på begge lister til sammen. To tellere settes til å peke på de første elementene i hver liste. Listene itereres til man har kikket gjennom begge listene. For hver iterasjon har man tre mulige utfall. 0 XOR 0 = 0 0 XOR 1 = 1 1 XOR 0 = 1 1 XOR 1 = 0 Figur 23 XOR operasjon Elementer i liste 1 er mindre enn elementet i liste 2. Elementet fra liste 1 legges til i liste 3. Peker 1 og 3 flyttes til neste felt. Elementer i liste 1 er større enn elementet i liste 2. Elementet fra liste 2 legges til i liste 3. Peker 2 og 3 flyttes til neste felt. Elementer i liste 1 er lik elementet i liste 2. Peker 1 og 2 flyttes til neste felt. Når en av pekerne når enden av listen plasseres de resterende elementene i de to første listene på slutten av liste 3. Deretter omformes liste 3 til en liste med det totalt antall like elementer fra liste 1 og 2. Denne returneres så tilbake. 35

Boolsk OR-operasjon Denne operasjonen skal finne de elementer som finnes i hvilken som helst av listene. Ved metodens oppstart genereres en liste tilsvarende lengden på begge lister til sammen. To tellere settes til å peke på de første elementene i hver liste. Listene itereres til man har kikket gjennom begge listene. For hver iterasjon har man tre mulige utfall. 0 OR 0 = 0 0 OR 1 = 1 1 OR 0 = 1 1 OR 1 = 1 Figur 24 OR operasjon Elementer i liste 1 er mindre enn elementet i liste 2. Elementet fra liste 1 legges til i liste 3. Peker 1 og 3 flyttes til neste felt. Elementer i liste 1 er større enn elementet i liste 2. Elementet fra liste 2 legges til i liste 3. Peker 2 og 3 flyttes til neste felt. Elementer i liste 1 er lik elementet i liste 2. Elementet legges til i liste 3. Peker 1, 2 og 3 flyttes til neste felt. Når en av pekerne når enden av listen plasseres de resterende elementene i de to første listene på slutten av liste 3. Deretter omformes liste 3 til en liste med det totalt antall like elementer fra liste 1 og 2. Denne returneres så tilbake. Boolsk NOT-operasjon Med denne operasjonen finner man alle forekomster som finnes i den ene listen minus de som finnes i den andre. Ved metodens oppstart genereres en liste tilsvarende lengden på begge lister til sammen. To tellere settes til å peke på de første elementene i hver liste. Listene itereres til man har kikket gjennom begge listene. For hver iterasjon har man tre mulige utfall. 0 NOT 0 = 0 0 NOT 1 = 0 1 NOT 0 = 1 1 NOT 1 = 0 Figur 25 NOT operasjon Elementer i liste 1 er mindre enn elementet i liste 2. Elementet fra liste 1 legges til i liste 3. Peker 1 og 3 flyttes til neste felt. Elementer i liste 1 er større enn elementet i liste 2. Peker 2 flyttes til neste felt. Elementer i liste 1 er lik elementet i liste 2. Peker 1 og 2 flyttes til neste felt. Når en av pekerne når enden av listen plasseres de resterende elementene i de den første listen på slutten av liste 3. Deretter omformes liste 3 til en liste med det totalt antall like elementer fra liste 1 og 2. Denne returneres så tilbake. 36

Komplekse boolske operasjoner De komplekse boolske operasjonene blir løst med splitt-og-hersk metodikk. Hver parentes behandles rekursivt av den samme metoden. På denne måten behandles de ytterste parentesene på det ytterste nivået mens indre operasjoner blir behandlet uten parenteser. Alle operasjoner resulterer i en liste som peker til de url-er man har lest inn ved oppstart. Uttrykk behandles fra venstre mot høyre. Dette resulterer i at uttrykk behandles som om man hadde brukt parentes rundt uttrykket helt til venstre, deretter en parentes rundt dette og neste operasjon osv. Hvis man skulle skrive et uttrykk uten boolske operasjoner, behandles hvert ord med en AND-operasjon. Dette medfører at dersom man skriver inn flere ord vil man søke etter alle sider som inneholder alle disse ordene. Startparentes Mellomrom Posisjon ( i t O R a k t u e l t ) A N D t e s t Figur 26 Parsing av angitt søketekst Den egentlige parsingen foregår ved at en peker plasseres på det første elementet i teksten. Ut fra hva denne posisjonen inneholder, kan flere ting skje. Elementet er en startparentes. Dersom parentes-telleren har verdien null, huskes denne posisjonen. Parentes-telleren inkrementeres. Elementet er en sluttparentes. Parentes-telleren dekrementeres. Dersom telleren har en verdi av null skilles teksten innenfor parentesen ut, og denne teksten parses uavhengig av annen tekst. Buffervariabelen settes til null. Mellomrom-pekeren settes til posisjonen etter parentesen. Elementet er et mellomrom. Det kontrolleres om forrige element også var et mellomrom. o Forrige element var et mellomrom. Sett mellomrom-pekeren til neste posisjon o Forrige element var ikke et mellomrom. Hent ut det forrige ordet. Søk har ikke blitt utført enda fremtil denne posisjonen. Ordet behandles som et vanlig søkeord uansett hva ordet består av. Dersom ordet er en boolsk operasjon og søk er utført. Den boolske operasjonen mellomlagres i en buffer-variabel. Alle andre tilfeller Søk blir utført på dette ordet med en påfølgende boolsk operasjon. Elementet er det siste i søketeksten. Det siste ordet hentes ut, og blir behandlet med en boolsk operasjon. 37