Søgemaskineprojekt. Analyse og implementering af en søgemaskine og en crawler til denne. Vejleder: Theis Rauhe (theis@it-c.dk)



Relaterede dokumenter
Hashing og hashtabeller

//Udskriver System.out.println("Hej " + ditfornavn + " " + ditefternavn + "."); System.out.println("Du er " + dinalder + " aar gammel!

DM01 DM Obl. Afl. Jacob Christiansen, , D12, Elias 18/ Side 1 af 11

Eksempel: Skat i år 2000

19 Hashtabeller. Noter. PS1 -- Hashtabeller. Hashing problemet. Hashfunktioner. Kollision. Søgning og indsættelse.

DM01 DM Obl. Afl. Jacob Christiansen, , D12, Elias 13/ Side 1 af 7

Målet for disse slides er at diskutere nogle metoder til at gemme og hente data effektivt.

University of Southern Denmark Syddansk Universitet. DM502 Forelæsning 3

Abstrakte datatyper C#-version

Forelæsning 17, tirsdag 2. november 1999 Søgning efter en given værdi i en tabel. Programmering 1999

Civilingeniøreksamen januar Skriftelig prøve den 12. januar 2001 Kursusnummer 49104

Kursus navn: Indledende programmering Kursus nr

Målet for disse slides er at beskrive nogle algoritmer og datastrukturer relateret til at gemme og hente data effektivt.

AAU, Programmering i Java Intern skriftlig prøve 18. maj 2007

University of Southern Denmark Syddansk Universitet. DM502 Forelæsning 2

Find største element, sæt det på sidste plads. Grundidé i hobsortering. er er

BRP Kursusintroduktion og Java-oversigt

Hanne Niels Edith Harald Carsten Jørgen Henrik.

Skriftlig eksamen i Datalogi

Lærevejledning. - en introduktion til maskinarkitektur. faraz@butt.dk Faraz Butt mads@danquah.dk Mads Danquah doktor@dyregod.dk Ulf Holm Nielsen

MySQL i Java. Tutorial lavet af Jákup W. Hansen TSU semester 05.januar 2007

Videregående Programmering Obligatorisk opgave - 3. semester, efterår 2004

Hashing og hashtabeller

Kursus i OOP og Java. Kursus i Objektorienteret programmering i Java

Tilgang til data. To udbredte metoder for at tilgå data: Sekventiel tilgang Random access: tilgang via ID (også kaldet key, nøgle) for dataelementer.

Tilgang til data. To udbredte metoder for at tilgå data: Sekventiel tilgang Random access: tilgang via ID (key, nøgle) for dataelementer.

Løsning af møntproblemet

University of Southern Denmark Syddansk Universitet. DM503 Forelæsning 11

Ugeseddel 4 1. marts - 8. marts

University of Southern Denmark Syddansk Universitet. DM502 Forelæsning 4

CD-DIRECT Installationsvejledning

Programmering i C. Lektion december 2008

Interaktionsudvikling

Martin Olsen. DM507 Projekt Del I. 19. marts 2012 FOTO: Colourbox

ELEKTRONISK INDBERETNING POST 23/ VERSION 1.13

DATALOGI 1E. Skriftlig eksamen torsdag den 3. juni 2004

RMI introduktion. Denne artikel beskriver Java RMI (Remtote Method Invocation).

Anamorphic Widescreen

Hashing. Hashing. Ordbøger. Ordbøger. Ordbøger Hægtet hashing Hashfunktioner Lineær probering. Ordbøger Hægtet hashing Hashfunktioner Lineær probering

Brug af Archive-funktion i SportIdent (baseret på version 10.3 af SI-programmerne)

Kom godt igang med Inventar registrering

Versionsbrev. LUDUS Web version Den 13. april J.nr V

Databaseadgang fra Java

Katalog sådan opdaterer du dine oplysninger til Danhostel-kataloget. Version 1.0 INDHOLDSFORTEGNELSE

Test af It-komponent

Hashing. Ordbøger Hægtet hashing Hashfunktioner Lineær probering. Philip Bille

Internetsøgemaskiner. Gerth Stølting Brodal Datalogisk Institut Aarhus Universitet

Software Construction 1 semester (SWC) Spørgsmål 1

Database optimering - Indeks

Danmarks Tekniske Universitet

DM507 Algoritmer og datastrukturer

Manual og Hjælp Skoletasken 2

Merging og Hashing (del I)

Danmarks Tekniske Universitet

Grafisk produktionsforståelse

MANUAL AF FILIP WALLBERG & RUNE MICHELSEN

Navision i undervisningen

Hashing. Ordbøger Hægtet hashing Hashfunktioner Lineær probering. Philip Bille

ELEKTRONISK INDBERETNING BØRNEDATABASEN VIA DGWS 13/ VERSION 1.02

Hashing. Hashing. Ordbøger. Ordbøger. Ordbøger Hægtet hashing Hashfunktioner Lineær probering. Ordbøger Hægtet hashing Hashfunktioner Lineær probering

Integrationsmanual. Anvendelse af webservice til kursusoversigt i Campus. Brugervejledning til udviklere

Computer netværk og TCP/IP protokoller. dcomnet 1

Quick guide. CLIQ Performer. ASSA ABLOY, the global leader in door opening solutions

I profil-feltet kan imastra-kunder vælge om upload skal ske ligesom filerne var indsendt til mailboksen eller

18 Multivejstræer og B-træer.

Datalogi OB, Efterår 2002 OH er, forelæsning 3/ forstå datastrukturer og algoritmer (teoretisk forståelse og intuition)

Versionsbrev. LUDUS Web version Den 8. august J.nr V

Her ser i hvorledes man nemt kan installere en række nyttige programmer, uden at få andet end selv programmet installeret. på

Programmeringscamp. Implementer funktionerne én for én og test hele tiden.

Sammenlign og byt. Et eksempel på dokumentering af et program

DM507 Algoritmer og datastrukturer

Forståelse for grafisk workflow

dmasark Aflevering - Uge 50

Installationsvejledning til LMeSmartClient

Dansk Ride Forbund Stævnesystem 2 Installationsvejledning

DANMARKS TEKNISKE UNIVERSITET

DM507 Algoritmer og datastrukturer

Versionsbrev. LUDUS Web version Den 27. maj J.nr V

Athena DIMENSION Varmeanlæg 4

Indhold. Vejledning til import af regneark til Outlook 2010

Eksterne Sundhedsinstitutioners import af sundhedsenheder til SOR

Skriftlig Eksamen DM507 Algoritmer og Datastrukturer

INFO DIAG DIAGNOSTICERINGS- VÆRKTØJ

b) Udvid din implementation af forme til at understøtte.equals. To objekter af samme form er ens hvis de har samme værdier i felterne.

Installér din Officepakke 2013

Brugervejledning til DHF's onlinesystem

Udbud.dk Brugervejledning til leverandører

Lectio. Overgang til Lectio Eksamensmodul. MaCom A/S Vesterbrogade 48, København V Telefon:

DRONNINGER (QUEENS) Opgave 1

Specifikation Abstrakt OO OS-API Rev Specifikation. Abstrakt, objektorienteret operativsystem-api

Indlæs Beretning på

Sekvensafstand DM34 - Eksamensopgave. Jacob Aae Mikkelsen

DM507 Algoritmer og datastrukturer

DM507 Algoritmer og datastrukturer

Whitepaper. Projektstatus, fasestatus og projektstadier. Indledning 2 Projektstatus og projektstadier 2

Studiepraktik. Thomas Bøgholm Mikkel Hansen Jacob Elefsen

Java Programmering. En bog for begyndere. Skrevet af Henrik Kressner

Serviceoperationer Puls

02101 Indledende Programmering Introduktion til Eclipse

Transkript:

Søgemaskineprojekt Analyse og implementering af en søgemaskine og en crawler til denne Morten Franck (skyfer@it-c.dk) Vejleder: Theis Rauhe (theis@it-c.dk) Peter G. Hansen (gath@it-c.dk) Påbegyndt den 25. november 2002. Aeveret den 20. december 2002 Gruppe 9, IT-Højskolen i København, Glentevej 67, 2400 København NV Abstract Med udgangspunkt i et projektoplæg fra IT-C, implementerer vi re udgaver af en søgemaskine, hvor de re implementeringer bliver trinvis bedre. Desuden analyseres plads- og tidsforbrug for de re søgemaskiner, og endelig udvikles en crawler som automatisk indsamler ord og URLs fra sider på Internettet. Keywords Hægtede lister, hashing, Big Oh, analyse af pladsforbrug og søgetider, crawlere, multithreading, JTidy

Indhold 1 Forord 1 1.1 Brug af symboler.................................. 1 2 Beskrivelse af dataler 2 3 SearchCmd1 2 4 SearchCmd2 3 5 Analyse af SearchCmd1 & SearchCmd2 3 5.1 Pladsforbrug (Antal objekter)........................... 4 5.2 Tidsforbrug (Opbygning)............................. 4 5.3 Tidsforbrug (Søgning)............................... 4 6 SearchCmd3 5 6.1 Datastrukturen................................... 5 6.2 Opbygning..................................... 5 6.3 Pladsforbrug (Antal objekter)........................... 6 6.4 Tidsforbrug (Opbygning)............................. 8 6.5 Tidsforbrug (Søgning)............................... 8 7 SearchCmd4 8 7.1 Datastrukturen................................... 9 7.2 Pladsforbrug (Antal objekter)........................... 10 7.3 Tidsforbrug (Opbygning)............................. 11 7.4 Tidsforbrug (Søgning)............................... 11 8 Konklusion på SearchCmd 12 9 Crawler 13 9.1 Programmets opbygning.............................. 13 9.2 Samtidighed..................................... 13 9.3 Programkørsel.................................... 14 9.4 Begrænsninger................................... 15 9.5 Test af crawleren.................................. 15 10 Konklusion på crawler 16

11 Litteratur 17 A Test 18 A.1 Whitebox-test af SearchCmd1........................... 18 A.2 Whitebox-test af SearchCmd2........................... 18 A.3 Whitebox-test af SearchCmd3........................... 19 A.4 Whitebox-test af SearchCmd4........................... 19 B Uddata fra SearchCmd5 (Crawler) 20 C Kildekode til SearchCmd1 21 D Kildekode til SearchCmd2 23 E Kildekode til SearchCmd3 24 F Kildekode til SearchCmd4 27 G Kildekode til SearchCmd5 (Crawler) 31 3

1 Forord Dette projekt tager udgangspunkt i projektforslaget fundet på http://www.it-c.dk/research/ algorithms/kurser/soegeprojekt/2002december/. Der er implementeret re forskellige søgemaskiner, der alle tager en tekstl som inddata og søger efter ord i denne. Søgemaskinerne bliver mere og mere avancerede, idet data gemmes og gennemsøges på mere og mere ranerede måder. For hver af de re søgemaskiner måles plads- og tidsforbruget og disse sammenlignes og konkluderes i afsnit 8. Der er foretaget tests af alle re søgemaskiner. Alle tests er foretaget på en Intel Pentium III 600 Mhz under Windows 2000 Server. Som udvidelse til ovenstående er der implementeret en såkaldt crawler, der bruger datastrukturen fra søgemaskine nr. 4. Crawleren søger HTML-ler igennem, gemmer links og ord fundet på disse og besøger derefter de fundne links. Testresultater fra de re søgemaskiner vericerer, at søgemaskinerne lever op til de tal, som man teoretisk set kan beregne sig frem til. 1.1 Brug af symboler N = Antal linier i datal og antal indlæsningsoperationer. M = Antal unikke ord i datal og antal indsættelsesoperationer. Alle andre symboler vil blive beskrevet der, hvor de bliver brugt. 2 Beskrivelse af dataler Datalerne brugt i første del af projektet, itcwww-small.txt, itcwww-medium.txt, itcwww-large.txt er struktureret på en bestemt måde og har følgende karakteristika: Der optræder præcist ét ord på hver linie i lerne, dvs. at en linie repræsenterer et ord. Hvis en linie starter med *PAGE er der tale om en URL. Den første linie i lerne er en URL. Alle URLs i en l er unikke, dvs. et URL forekommer een og kun een gang i hver l. På linierne efter en linie, der starter med *PAGE, kommer de ord, der forekommer på denne URL. Filerne kommer i tre størrelser: Den mindste (itcwww-small.txt) er ca. 27 KB stor, den mellemste (itcwww-medium.txt) er på ca. 1,5 MB, og den største (itcwww-large.txt) er ca. 20 MB stor. 3 SearchCmd1 Denne søgemaskine tager en tekstl som inddata og gør det muligt for brugeren at skrive et ord, som denne vil søge efter. Søgningen resulterer i et ja eller nej. 1

Indledningsvis bemærkes det, at i såvel SearchCmd1 som SearchCmd2, indlæses alle linier fra len ukritisk uden at undersøge om der er tale om et almindeligt ord, eller om der er tale om en URL. str next "*PAGE:http://www.dmi.dk" *PAGE:http://www.dmi.dk Tordenvejr *PAGE:http://www.dr.dk TV Avisen str next str next "Tordenvejr" "*PAGE:http://www.dr.dk" str next "TV Avisen" Figur 1: Et uddrag af len itcwww-small.txt samt den tilhørende datastruktur for SearchCmd1 og SearchCmd2. Linierne fra len indlæses i en hægtet liste, som består af to elementer: et ord fra len samt en pegepind til det næste element i listen (som er et element af samme type). Måden, hvorpå opbygningen af listen sker, er ved at indlæse det første ord fra len i et nyt liste-element og sætte dettes næste-pegepind til en tom værdi (). Der gemmes en særlig pegepind til dette første element, som ikke bliver ændret gennem opbygningen af listen. Herefter læses ordene ind fra len ét efter ét og for hvert ord oprettes et nyt listeelement, som det foregående elements næste-pegepind sættes til at pege på. Indlæsningen stopper, når der forekommer en tom værdi i tekstlen. Dermed peger det sidste elements næste-pegepind på, og dette bruges som termineringsbetingelse. Når opbygningen af den hægtede liste er færdig, skal det være muligt at søge i denne. Dette sker ved at traversere listen fra den førnævnte pegepind til det første element i listen og for hvert ord i listen sammenligne med det af brugeren indtastede ord. Er ordene de samme returneres med en Ja-værdi, ellers sammenlignes med næste element, indtil der ikke er ere elementer i listen, hvorefter en Nej-værdi returneres. "En" "to" "tre" "fire" start str str str str next next next next Figur 2: Datastrukturen for SearchCmd2, bestående af en enkelt hægtet liste. Det bemærkes, at der er ere ulemper ved datastrukturen brugt i SearchCmd1: De samme ord indsættes ere gange, dvs. der er dubletter. Der skelnes ikke mellem ord og URLs, og det er derfor ikke muligt at svare på, hvilke ord, der forekommer på hvilke sider. I afsnit 5.2 og 5.3 vil opbygning af og søgning i datastrukturen blive gennemgået. 2

4 SearchCmd2 Denne søgemaskine tager en tekstl som inddata og gør det muligt for brugeren at skrive et ord, som denne vil søge efter. Søgningen resulterer i en liste af unikke Internet-adresser (URLs), hvorpå det eftersøgte ord, forekommer. Opbygningen af den hægtede liste sker på samme måde som i programmet SearchCmd1; det vil sige, at den underliggende datastruktur er den samme. I stedet for at returnere et positivt eller negativt svar på hvorvidt et givet ord ndes i tekstlen, skal det dog nu være muligt at returnere en liste over de URLs, hvorpå søgeordet forekommer. Linierne fra len indlæses ligesom i SearchCmd1, og når et ord starter med '*', gemmes den pågældende URL. Herefter undersøges det om det aktuelle ord i listen er det samme som søgeordet, samt om ordet allerede er fundet på denne side før. Det sidste check laves for at undgå, at den samme URL returneres ere gange, hvis det samme ord optræder ere gange på den. Det endelige resultat er en liste over de URLs, som det af brugeren indtastede ord, optræder på. Det er vigtigt at bemærke, at det i SearchCmd2 kun er muligt at generere en liste af adresser for ét ord. Det er ikke muligt at generere en liste over alle ord, og hvilke sider disse forekommer på. 5 Analyse af SearchCmd1 & SearchCmd2 Et af de største problemer med datastrukturen i SearchCmd1 og SearchCmd2 er, at den indeholder dubletter. Ydermere er der ingen adskillelse af ord og URLs, når disse indlæses i den hægtede liste fra len. Opbygning af listen sker ved ukritisk at indlæse alle linier uden hensyn til, om der er tale om et ord eller en URL, samt om ordet allerede er sat ind. Søgning i listen er ikke optimal, da man i værste tilfælde bliver nødt til at løbe hele listen igennem, og ydermere er der ikke direkte adgang til et vilkårligt element i listen (i modsætning til eksempelvis arrays). Dette skyldes dog hægtede listers natur. 5.1 Pladsforbrug (Antal objekter) Antallet af objekter i såvel SearchCmd1 som SearchCmd2 er proportionalt med N, fordi for hver linie i len oprettes et ord-liste-objekt og et streng-objekt. For hvert ord-liste-objekt er der to referencer, der hver fylder re bytes: 4 bytes til en reference til et streng-objekt. 4 bytes til en reference til det næste element i listen. Dette betyder, at for hver linie i len bruges der 8 bytes til referencer i hukommelsen. Javas egne administrative informationer og diverse hjælp-objekter (eksempelvis en BufferedInputReader er ikke medregnet. Ud over referencer optager streng-objekterne det antal bytes som en linie i len fylder. Tabel 1 viser det samlede antal objekter, der bliver oprettet SearchCmd1 og SearchCmd2 samt det antal kilobytes, som disse fylder for hver af de tre dataler. Antal objekter: 2N Antal kilobytes: 3

Antal objekter Samlet pladsforbrug (KB) itcwww-small.txt 8000 55 itcwww-medium.txt 210000 3147 itcwww-big.txt 2742137 39385 Tabel 1: Antal objekter og pladsforbrug for SearchCmd1 og SearchCmd2 Opbygning Søgning: Søgning: bedste tilfælde værste tilfælde itcwww-small.txt 90 0 0 itcwww-medium.txt 1963 0 60 itcwww-big.txt Java.lang.OutOfMemoryError Ikke muligt Ikke muligt Tabel 2: Tidsforbrug for SearchCmd1 og SearchCmd2 8N + N i=1 l i 1000 hvor N er antal linier i datalen og l i er længden af streng-konstanten. 5.2 Tidsforbrug (Opbygning) Opbygningstiden er proportional med N, dvs. O(N). 5.3 Tidsforbrug (Søgning) Værste tilfælde: O(N) Bedste tilfælde: 1 I gennemsnit: N/2 Den gennemsnitlige værdi dækker over tiden for søgning på et tilfældigt ord, hvor sandsynligheden for at dette forekommer i len er 50%. Bemærk, at der ses bort fra gennemløb af URL-lister i søgningen, da disse ikke søges igennem, men kun udskrives når søgeordet er fundet. Tabel 2 viser tidsforbruget for SearchCmd1 og SearchCmd2 for de tre dataler. Alle tider er angivet i millisekunder. Af åbenlyse årsager vil der være forskel i søgetider for det ord, der forekommer som det første i len (og dermed også som det første i listen), og det ord, der forekommer som det sidste i len. For at kunne lave en søgning på det værste tilfælde, søges på et ord, der ikke forekommer i len (da hele listen så vil blive løbet igennem). Søgning er af naturlige årsager ikke muligt at udføre, da listen ikke bliver opbygget. 4

6 SearchCmd3 Der er ere gode grunde til at lave om på datastrukturen brugt i de to første udgaver af SearchCmd. Den vigtigste grund er pladsforbruget, som er proportionalt med inddatas størrelse. Helt nøjagtigt er der et 1:1-forhold mellem N og antal objekter i SearchCmd1 og SearchCmd2. Pladsforbruget søges derfor nedbragt i SearchCmd3. 6.1 Datastrukturen Datastrukturen i den tredje udgave af søgemaskinen adskiller sig væsentligt fra de to første, idet den ikke længere består af en enkelt hægtet liste, men af mange hægtede lister. Datastrukturen kan ses på Figur 3 og vil blive gennemgået i det følgende. Overordnet er der tale om to typer af lister, en horisontal og en vertikal (se Figur 3). Hvert element i den vertikale liste indeholder en reference til et ord i len, som gennemsøges, og den komplette vertikale liste består af præcis ét element for hvert unikt ord i len. Hvert af disse elementer indeholder også en reference til det første element i en horisontal liste. Hvert af elementerne i den horisontale liste indeholder en reference til en adresse (en URL), hvorpå det pågældende ord forekommer, samt en reference til det næste element i den horisontale liste. Modsat SearchCmd1 og SearchCmd2 gør denne datastruktur det muligt for alle ord at udskrive de URLs, hvorpå de forekommer. Dette sker ved for hvert ord i den vertikale at udskrive hele den horisontale liste. "www.dmi.dk" "This" str url next Addr next "www.dr.dk" "New" str url next Addr next next Addr "www.tv2.dk" "www.google.com" "www.cybercity.dk" "page" str url next Addr next Addr next Addr next Addr next URL liste objekt str url next Ord liste objekt "www.cybercity.dk" URL streng objekt "page" Ord streng objekt Figur 3: Datastrukturen for SearchCmd3, bestående af horisontale og vertikale lister. 5

6.2 Opbygning Opbygningen af listerne foregår ved at læse et ord fra len og derefter løbe den vertikale liste igennem for at afgøre, om det netop læste ord allerede ndes i listen. Hvis dette ikke er tilfældet, indsættes ordet i den vertikale liste og den aktuelle URL indsættes som det første element i det pågældende ords URL-liste (den horisontale liste). Hvis ordet allerede står i listen, undersøges det første element i ordets URL-liste, og hvis dette ikke er lig med den aktuelle URL, indsættes den aktuelle URL som det første element i URL-listen. Da URLs optræder præcis én gang i datalen, kan vi være sikre på, at hvis et givet URL er i det pågældende ords URL-liste, vil det stå som det sidst indsatte element, og vi behøver derfor ikke løbe URL-listen igennem for at undersøge om en given URL allerede er indsat. Sammenligningen af de to URLs sker vha. == i stedet for den langsommere equals()- metode, fordi der kun oprettes ét streng-objekt pr. URL i len, og hvis den aktuelle URL derfor skal være lig den første i URL-listen, må den nødvendigvis stå på samme adresse i hukommelsen (da der i dette tilfælde er tale om to referencer til det samme objekt). Efter en eventuel indsættelse af det et element i den horisontale liste, udvælges det næste element til den vertikale liste som beskrevet ovenfor, og denne procedure fortsætter indtil alle ord i len er repræsenteret præcis én gang i den vertikale liste. 6.3 Pladsforbrug (Antal objekter) Der bliver oprettet to objekter for hvert unikt ord i len: ét ord-liste-objekt samt et ordstreng-objekt. Ydermere bliver der oprettet et URL-liste-objekt pr. URL i len samt et tilhørende URL-streng-objekt pr. unik URL i len. Dette betyder følgende: Antallet af ord-liste-objekter vil blive reduceret, da dubletter fjernes fra strukturen. Antallet af URL-streng-objekter vil være det samme som antallet af ord-streng-objekter for de linier hvorpå, der stod *PAGE i SearchCmd1 og SearchCmd2, men det samlede antal objekter vil dog blive forøget med det antal URL-liste-objekter, som der nu ndes. Som det ses på Figur 3 kan URL-liste-objekterne dele de streng-objekter, som selve URLadressen indlæses i. Dette er muligt fordi URLs kun optræder én gang i len og dermed kun indlæses én gang i programmet, og der dermed kun bliver oprettet ét streng-objekt pr. unik URL. Det samlede antal objekter i SearchCmd3 kan udtrykkes ved: hvor 2M + P + Q M Antal ord-liste-objekter. P Antal unikke URL-streng-objekter. Q Antal URL-liste-objekter. Hvert ord-liste-objekt fylder i alt 12 bytes: 4 bytes til referencen til ord-streng-objektet. 6

Antal objekter Samlet pladsforbrug (KB) itcwww-small.txt 4179 39 itcwww-medium.txt 149497 1321 itcwww-big.txt 1082699 9594 Tabel 3: Antal objekter og pladsforbrug for SearchCmd3 4 bytes til referencen til det næste ord-liste-objekt. 4 bytes til referencen til et URL-liste-objekt. Hvert URL-liste-objekt fylder i alt 8 bytes: 4 bytes til referencen til URL-streng-objektet. 4 bytes til referencen til det næste URL-liste-objekt. Tabel 3 viser det antal kilobytes, der bliver brugt for hver af de tre dataler i SearchCmd3 til henholdsvis ord-streng-objekter samt URL-streng-objekter. Antal kilobytes: hvor 12M + K + 8Q + T 1000 K er den samlede længde af unikke ord-streng-objekter. T er den samlede længde af unikke URL-streng-objekter. 6.4 Tidsforbrug (Opbygning) Givet at der er N linier i len totalt set, og at disse linier bliver læst og behandlet en for en, giver dette i sig selv N operationer. Udover disse N operationer, løbes den vertikale liste igennem for hvert ord der læses fra len for at undersøge, om det netop læste ord står der i forvejen. Dette svarer til M operationer, og det tager derfor i værste fald N M operationer at opbygge listen. Dette kan udtrykkes ved: Opbygningstiden er proportional med antal indlæsningsoperationer gange antal indsættelsesoperationer, dvs. O(NM) Sammenlignet med SearchCmd1 og SearchCmd2, hvor det tager N operationer at opbygge listen, er tidsforbruget her højere, da der er det krav, at ordene i den vertikale liste skal være unikke. 6.5 Tidsforbrug (Søgning) Søgningen foregår ved at sammenligne elementerne i den vertikale liste med søgeordet. Søgningen gennem listen foregår sekventielt. 7

Opbygning Søgning: bedste tilfælde Søgning: værste tilfælde itcwww-small.txt 600 0 5 itcwww-medium.txt Ikke praktisk muligt Ikke muligt Ikke muligt itcwww-big.txt Ikke praktisk muligt Ikke muligt Ikke muligt Værste tilfælde: O(M) Bedste tilfælde: O(1) I gennemsnit: O(M/2) Tabel 4: Tidsforbrug for SearchCmd3 I alle tilfælde ses naturligvis bort fra antallet af URL-liste-objekter, som hvert ord refererer til, idet disse ikke søges igennem. Tabel 4 viser tidsforbruget for SearchCmd3 for de tre dataler. Alle tider er angivet i millisekunder. Udtrykket Ikke praktisk muligt dækker her over at tidsforbruget for opbygning er proportionalt med MN, og derfor vil tiden for opbygningen overstige en tid, som denne gruppe opfatter som praktisk brugbar. 7 SearchCmd4 Hvor størrelsen på datastrukturen blev drastisk formindsket fra SearchCmd1 og SearchCmd2 til SearchCmd3, tager det stadig forholdsvis lang tid at gennemsøge og især opbygge datastrukturen. Disse to faktorer vil blive dramatisk forbedret i SearchCmd4, se Tabel 6. Dette sker ved brug af hashing til hurtigt at placere og fremnde et givet ord i datastrukturen, som det vil blive beskrevet nedenfor. 7.1 Datastrukturen Som det ses på Figur 4 tilføjes et ekstra led til datastrukturen. Dette led er et array. Hver plads i arrayet refererer nu til en ord-liste (som måske kun er ét element lang). Som i de andre SearchCmd-programmer, refererer et ord-liste-objekt til en URL-liste. Arrayet fungerer som en hash-tabel. Ud fra hvert unikt ord, x, der ndes i len, beregnes et indeks i vha. en hash-funktion, h(x), og denne værdi svarer til en indgang i arrayet. For at sikre at 0 i S 1, hvor M er antallet af indgange i arrayet, beregnes: i = h(x) modulo M Der udstedes ikke garanti for, at i er unik for alle x, dvs. to forskellige ord godt kan resultere i det samme indeks; dette kaldes en kollision. Mere præcist opstår en kollision for en hashfunktion, h, hvis h(x) = h(y), men x y. Hvis en kollision skulle opstå, vil det ord, som kolliderer med et allerede indsat ord - dvs. det ord, hvis hash-værdi er den samme - blive indsat forrest i den ord-liste, hvis start-reference ndes på den pågældende plads i arrayet. Længden af disse lister vil afhænge af forholdet mellem det antal ord, der skal indsættes og antal indgange i hash-tabellen. Dette forhold kaldes hash-tabellens load factor og siger noget om, hvor fyldt hash-tabellen er: 8

0 "Collision" "occurred" 1 str next url str url next 2 3 Addr next "www.dmi.dk" Addr next "www.sony.com" hashcode() 4 Addr "www.who.dk" "IT" next n 3 n 2 n 1 str url Addr next "www.dr.dk Addr next Figur 4: Datastrukturen for SearchCmd4, bestående af et array (en hash-tabel), horisontale hægtede lister indeholdende unikke ord, samt vertikale hægtede lister indeholdende URLs på de sider, hvor et ord forekommer. Load factor L = M HASH_TABLE_SIZE Hvis L > 1 er der kollision i hash-tabellen, men denne er ikke nødvendigvis fuld, da man kan bruge såkaldt chained hashing, hvor hver indgang i hash-tabellen refererer til en datastruktur, i vores tilfælde, en hægtet liste. Antallet af kollisioner begrænses ved brug af en god hashfunktion, dvs. en funktion, der spreder inddata så meget som muligt ud over hele tabellen, samt ved at vælge en fornuftig størrelse på sin hash-tabel. Det er en afvejning om man vil lave sin hash-tabel stor og så vidt muligt undgå kollisioner, men dermed bruge mere hukommelse eller om man vil lave en mindre tabel, der bruger mindre hukommelse, men til gengæld tager længere tid at opbygge og søge i (pga. ere elementer i de hægtede lister). I vores program bruger vi Javas hashcode()-funktion og fordobling af tabellen samt genberegning af hash-værdier for alle indsatte ord, når L > 0.75. Denne værdi er ved test fundet til at være en god værdi til at minimere antallet af kollisioner og samtidig holde pladsforbruget nede. Fordoblingen af tabellen sker ved at genberegne hash-værdier for alle ord-streng-objekter og derefter genopbygge ord-listerne i den nye og dobbelt så store hashtabel, se Figur 5. Bemærk at de ord, der hashede til samme værdi i den gamle tabel, ikke nødvendigvis vil hashe til samme værdi i den nye tabel, og derfor ikke kommer til at være elementer i samme ord-liste. 7.2 Pladsforbrug (Antal objekter) SearchCmd4 er en udvidelse af SearchCmd3, da der i SearchCmd4 bruges en hash-tabel ud over de to hægtede lister fra SearchCmd3. Derfor vil der være det samme antal objekter i SearchCmd4 som i SearchCmd3, da det man dybest set gør er at fordele den vertikale liste fra SearchCmd3 ud i forskellige pladser i arrayet i SearchCmd4. Den eneste forskel i pladsforbruget er den plads, som hash-tabellen optager, nemlig 16 bytes for at angive, at vi arbejder med at array samt 4M bytes til referencer til ord-listerne. 9

0 1 0 a 2 3 a 1 4 b 2 b c 5 d 3 6 4 d 7 c L = 4/5 = 0,80 = 80% 8 9 L = 4/10 = 0,40 = 40% Figur 5: Illustration af princippet i rehashing. Alle elementer i arrayet samt eventuelle hægtede lister gennemløbes og for hvert element beregnes en ny hash-værdi i den nye hashtabel. Antal objekter: Antal fra SearchCmd3 + minimum M, da der minimum vil være M indgange i arrayet, nemlig én for hvert unikt ord. Typisk vil arrayet dog være blevet fordoblet en eller ere gange, hvorfor der vil være blevet oprettet ere indgange. Antal kilobytes: Antal kilobytes fra SearchCmd3 + minimum 12M 1000. Tabel 5 viser det samlede antal objekter, der bliver oprettet i SearchCmd4 samt det antal kilobytes, som disse objekter fylder for hver af de tre dataler. Det bemærkes, at antallet af ord-liste-objekter (og dermed det samlede antal), afhænger af, hvad hash-tabellens størrelse er sat til fra start. Tallene i Tabel 5 er beregnet ud fra en initiel hash-tabel-størrelse på 3. 7.3 Tidsforbrug (Opbygning) Opbygningen af datastrukturen er dramatisk hurtigere, da der bruges hashing i stedet for gennemløb af lister. Indsættelsesoperationer er her konstante, da det tager konstant tid at beregne hash-værdi samt indsætte i starten af den tilhørende hægtede ord-liste men tiden det tager at løbe len igennem er naturligvis stadig proportional med N. Opbygningstiden bliver derfor: O(1N) = O(N) 7.4 Tidsforbrug (Søgning) I en hægtet liste foregår søgning altid sekventielt, hvorimod man i et array (en hash-tabel) kan slå direkte op på en bestemt plads, hvis man har et indeks. Måden at søge på i SearchCmd4 er at beregne et indeks, i, for det ønskede ord og derefter gennemløbe ordlisten på plads nr. i i arrayet. Denne måde at slå op i tabellen på er dramatisk hurtigere end et gennemløb af en hægtet liste, da man blot ved at beregne en hash-værdi for søgeordet minimerer søgerummet til en liste på 1-5 elementer. Dog bemærkes det, at hvis søgeordet står som et af de første (5) elementer i SearchCmd3 vil søgningen naturligvis gå lige så hurtigt i SearchCmd3 som i SearchCmd4. Som nævnt i sidste afsnit tager det konstant tid at beregne en hash-værdi, og hvis hash- 10

Antal objekter Samlet pladsforbrug (KB) itcwww-small.txt 5715 57 itcwww-medium.txt 174073 1616 itcwww-big.txt 1181003 10482 Tabel 5: Antal objekter og pladsforbrug for SearchCmd4 Opbygning Søgning itcwww-small.txt 131 0 itcwww-medium.txt 1683 0 itcwww-big.txt 15722 0 Tabel 6: Tidsforbrug for SearchCmd4 tabellen fordobles når L > 0.75, vil ord-listerne have en gennemsnitslængde på mellem 1 og 5 elementer, og tiden det tager at gennemløbe disse lister er derfor negligérbar. Søgetiden i SearchCmd4 er altså konstant, dvs. O(1). Tabel 6 viser tidsforbruget for SearchCmd4 for de tre dataler. Alle tider er angivet i millisekunder. Som det ses af Tabel 6, er alle søgetider 0. Dette skyldes, at Java-funktionen CurrentMillis() kun kan returnere et antal millisekunder samt at det tager under ét millisekund at udregne en hash-værdi for søgeordet og at løbe den eventuelle ord-liste igennem. Derfor har vi lavet gentagne søgninger og derefter divideret den forløbne tid med antal søgninger for at få tiden for én søgning. 1000000 søgninger på et tilfældigt ord 1 tager i snit (for en vilkårlig af de tre dataler) ca. 500 ms, altså ca. 0,0005 ms for én søgning. 8 Konklusion på SearchCmd Nedenstående liste viser de vigtigste karakteristika ved hver af de re søgemaskiner. SearchCmd1 Dubletter medtages. Ja/Nej svar på søgning. SearchCmd2 Dubletter medtages. Liste over URLs for søgeord. SearchCmd3 Ingen dubletter. Liste over URLs for alle unikke ord. SearchCmd4 Dramatisk hurtigere opbygning og søgning end SearchCmd3. Tabel 7 og Tabel 8 viser en oversigt over plads- og tidsforbruget for itcwww-big.txt for de re søgemaskiner. Tiden for søgning er gennemsnittet af det bedste og værste tilfælde. Det ses af Tabel 7, at forskellen i pladsforbruget mellem SearchCmd3 og SearchCmd4 er antallet af bytes brugt til hash-tabellen, nemlig M gange 12 bytes. I SearchCmd3 og SearchCmd4 er dubletter sorteret fra, og dette resulterer naturligvis i færre ord-liste-objekter og samlet set i en mindre datastruktur. Helt præcist vil der blive oprettet 1/R ord-liste-objekter i SearchCmd3 i forhold til i SearchCmd1 og SearchCmd2, hvis et ord forekommer R gange på en side. Dette indses, da der for hver gang der bliver oprettet et ordliste-objekt i SearchCmd1 og SearchCmd2 kun bliver oprettet et ord-liste-objekt hver R'te gang i SearchCmd3, dvs. et for hvert unikt ord. Dog kommer der så URL-liste-objekterne 1 Tilfældigheden genereres af Javas Math.random()-metode 11

Antal objekter Samlet pladsforbrug (KB) SearchCmd1+2 2742137 39385 SearchCmd3 1082699 9594 SearchCmd4 1181003 10482 Tabel 7: Oversigt over pladsforbrug for SearchCmdX Opbygning (ms) Søgning (ms) SearchCmd1+2 Java.lang.OutOfMemoryError Ikke muligt SearchCmd3 Ikke praktisk muligt Ikke muligt SearchCmd4 15402 0,0005 Tabel 8: Oversigt over tidsforbrug for SearchCmdX oveni pladsforbruget i SearchCmd3 (og SearchCmd4), men hvert af disse objekter fylder mindre end et ord-liste-objekt (8 bytes i stedet for 12 bytes), og nogle af disse URL-listeobjekter deler streng-objekter. Denne deling sker ikke i SearchCmd1 og SearchCmd2. Til trods for at det ikke er praktisk muligt at opbygge listen i SearchCmd3, ved vi, at søgetiden vil være kortere end i SearchCmd1 og SearchCmd2, fordi der sorteres dubletter fra. Dette er dog også årsagen til at opbygningstiden i praksis ikke er mulig allerede ved itcwww-medium.txt. I SearchCmd4 løses problemet med den lange opbygningstid ved at bruge hashing. Denne metode sikrer, at opbygningen kan ske i en tid proportional med N, da man kan se bort fra gennemløbet af de 15 elementer lange ord-lister. Dette, samt dét at en hash-værdi beregnes i konstant tid, betyder også, at søgning i SearchCmd4 sker i konstant tid. 9 Crawler Vi har som udvidelse til dette projekt valgt at lave en crawler. En crawler er den del af en søgemaskine, der givet en URL-adresse (en HTML-l) som en inddata, søger denne igennem og leder efter links til andre sider. Disse links gemmes og vil senere selv blive besøgt og søgt igennem for nye links. Vi vil i det følgende beskrive de hovedområder og problemstillinger som en crawler indeholder. Til implementering af crawleren bruges en Java-pakke lavet af W3C, JTidy 2, der udbyder funktionalitet til givet en HTML-l som inddata at gemme denne l som en træstruktur, søge dette træ igennem og udvælge navne og værdier for de elementer og den tekst, der forekommer i HTML-len med andre ord en HTML parser. 9.1 Programmets opbygning Figur 6 viser de vigtigste elementer i programmet. Hver crawler-tråd, der startes i programmet (jf. afsnit 9.3) indeholder to referencer, der peger på henholdsvis det samme URLTableobjekt og DataTable-objekt. Dette eneste URLTable-objekt indeholder selv kun én reference til en datastruktur af den type beskrevet i kapitel 7.1 (CrawlerURLs). På lignende måde indeholder det ene DataTable-objekt, der ndes, kun én reference til en datastruktur af den type beskrevet i kapitel 7.1 (CrawlerData). CrawlerURLs gemmer de sider, som er blevet crawlet og som skal crawles. CrawlerData gemmer de ord, som er fundet på de URLs, der er blevet crawlet, samt hvilke URLs disse ord forekom på (samme type som i SearchCmd4. 2 Denne pakke kan hentes på http://sourceforge.net/projects/jtidy. 12

Såvel URLTable-klassen som DataTable-klassen har ydermere en metode til at fordoble hashtabellen og genberegne hash-værdier. Crawler-objekterne står for at hente ord og URLs ud af de HTML-ler, som der peges på i CrawlerURLs-strukturen. PageData URLs HTMLlist URLTable DataTable CrawlerURLs[] cu; CrawlerData[] cd; Crawler Crawler Crawler Crawler Crawlers[] c; Monitor Figur 6: Oversigt over forskellige klasser brugt i crawleren. CrawlerURLs og CrawlerData objekterne deles af alle crawler-tråde. Når en crawler-tråd skal hente en ny URL fra URL-tabellen sker dette ved lineær søgning gennem URL-tabellen, da man ikke på forhånd kan vide, hvilke URLs, der er besøgt, og hvilke der ikke er. Første gang man støder på en URL, der ikke er besøgt, markeres denne som værende besøgt, og URL'en returneres til crawler-tråden. 9.2 Samtidighed Crawleren er ertrådet, hvilket betyder, at der er ere tråde 3, der kan køre semi-parallelt på et system med én CPU. Dette medfører naturligvis nogle begræsninger på hvornår datastrukturerne må blive opdateret, da det er vigtigt, at de samme data ikke indsættes to gange af to forskellige tråde. Denne begrænsning implementeres i vores program ved at bruge Javas synchronizedkonstruktion til at gøre datastrukturerne til kritiske regioner, der kun kan opdateres af én tråd ad gangen. JRE'en styrer selv tilgangen til de kritiske regioner, og sørger for at hvis én tråd forsøger at opdatere en af de beskyttede datastrukturer mens en anden er igang, vil den, der forsøger at opnå adgang, blive sat til at vente. Ydermere sørger JRE'en for, at når en tråd er færdig med at bruge den kritiske region, får eventuelle ventende tråde besked om 3 I Windows bruges tråde, i Linux bruges børne-processer 13

dette, og JRE'en udvælger en af de ventende tråde, som den der får lov at bruge den kritiske region. De kritiske regioner er de steder i vores program hvor vi tilgår datastrukturen indeholdende ord fundet på de besøgte URLs (CrawlerData) samt de steder hvor vi tilgår datastrukturen indeholdende links (CrawlerURLs). Dette vil sige, at vi i de tre metoder, der tilgår disse to datastrukturer, henholdsvis insertword(), geturl() og addurl() skal sørge for at beskytte datastrukturerne fra samtidig opdatering af ere tråde. Dette gøres ved inden i de tre førnævnte metoder at synkronisere den blok kode, der bruger (opdaterer) den pågældende datastruktur. Det forhindres at en crawler-tråd forsøger at hente en ikke-besøgt URL fra CrawlerURLsstrukturen, hvis strukturen enten er tom, eller URLs i strukturen allerede er besøgt. Dette sker ved at tråden sættes til at vente ved at kalde wait()-metoden. Tilsvarende sørges for at vække eventuelle blokerede tråde, der måtte have kaldt wait(), ved at kalde notifyall()- metoden, når en ny URL indsættes i CrawlerURLs-strukturen. Deadlock er ikke muligt i programmet, da hver tråd kun bruger én ressource ad gangen (enten CrawlerURLs eller CrawlerData) og derefter frigiver låsen på denne ressource. 9.3 Programkørsel Det første, der sker, når programmet startes er, at der fra brugerens side indsættes en URL i URL-tabellen. Dette sker, så den første crawler, der startes, har noget at hente. Herefter startes et statisk antal crawler-tråde. Når en crawler har hentet en URL fra CrawlerURLs-strukturen, oprettes en forbindelse. Herefter undersøges HTTP-headeren og, hvis der er tale om en almindelig HTML-l (eller lignende), sættes crawler-tråden til at traversere det træ, som parsedom()-metoden (fra JTidy-pakken) med URL'en som inddata returnerer. I dette træ søges efter links - dvs. elementer, der ikke er almindelig tekst, og som har en href-attribut - og disse links gemmes ned i CrawlerURLs-strukturen, hvis ikke de står der i forvejen. URLs, der indsættes i CrawlerURLs, vil som standard være markeret som ikke-besøgt. I traverseringen af træet indsættes også de unikke ord, der forekommer på den givne URL. På denne måde fortsættes indtil enten alle URLs i CrawlerURLs er sat som værende besøgt og ingen af disse URLs linker til URLs, der ikke i forvejen står i URL-tabellen eller indtil der ikke er mere hukommelse til rådighed i systemet. 9.4 Begrænsninger Sammenlignes den implementerede crawler med eksempelvis den, som man kunne forestille sig at Google har, er vores meget primitiv og er afgrænset på mange områder. Følgende lister de vigtigste begrænsninger i vores crawler: Kun links af typen text/html crawles. Links til alle andre typer gemmes ikke. Kun absolutte HTTP-adresser (URLs der starter med http eller www) gemmes. Relative URLs og eks. mailto:, ftp- og news-adresser gemmes ikke. Udover dokumenttypen undersøges ingen andre felter i HTTP-headeren i svaret fra serveren. Eks. checkes der ikke for 404- (File not found) og 500-fejl (Internal server error). Der tages ikke hensyn til robots.txt. 14

Der startes et statisk antal crawler-tråde. I en mere avanceret implementering kunne man forestille sig dynamisk at starte et antal crawler-tråde alt efter hvad der var ressourcer til. 9.5 Test af crawleren Crawleren fungerer hvis og kun hvis alle links i URL-tabellen crawles, dvs. deres træ traverseres, unikke ord gemmes og unikke links gemmes, hvis de ikke er besøgt i forvejen. Dette vericeres ved en black-box-test. Først udføres en test, hvor crawleren får en lille HTML-l lavet til formålet som inddata. Denne HTML-l indeholder kun få ord samt et link til en anden lille HTML-l også lavet til formålet. Den anden HTML-l indeholder et link tilbage til den første HTML-l, og crawleren skal derfor kun crawle hver af siderne een gang. Siden http://xslt.it-c.dk/~skyfer/disko.html linker til http://xslt.it-c.dk/~skyfer/test.html Siden http://xslt.it-c.dk/~skyfer/disko.html linker til http://xslt.it-c.dk/~skyfer/test.html Siden http://xslt.it-c.dk/~skyfer/test.html linker til http://xslt.it-c.dk/~skyfer/disko.html jytte http://xslt.it-c.dk/~skyfer/test.html http://xslt.it-c.dk/~skyfer/disko.html bar http://xslt.it-c.dk/~skyfer/test.html http://xslt.it-c.dk/~skyfer/disko.html niels http://xslt.it-c.dk/~skyfer/disko.html jack http://xslt.it-c.dk/~skyfer/test.html http://xslt.it-c.dk/~skyfer/disko.html skoven http://xslt.it-c.dk/~skyfer/test.html http://xslt.it-c.dk/~skyfer/disko.html jacksonsen http://xslt.it-c.dk/~skyfer/test.html http://xslt.it-c.dk/~skyfer/disko.html Foo http://xslt.it-c.dk/~skyfer/test.html http://xslt.it-c.dk/~skyfer/disko.html Ud fra ovenstående uddata, samt kravene nævnt i indledningen til dette afsnit, vericeres det, at crawleren fungerer. En større og mere virkelig test, hvor crawleren får URL'en http://www.w3.org som inddata kan ses i bilag B. 10 Konklusion på crawler Det er lykkedes at implementere en crawler, der lever op til de mest basale krav. Ved test af crawleren med URL http://www.w3.org som inddata, kører crawleren et stykke tid, men stopper på et tidspunkt af ukendte årsager. Vi mistænker Jtidy-pakken for at generere 15

nogle fejl, som vi ikke får håndteret på en måde, der kan sikre videre programudførsel. Formodningen baseres på, at der crawles et større antal sider, inden programmet standser. 16

11 Litteratur Wigglesworth & Lumby: Java Programming: Advancted Topics, Thomson Learning, ISBN: 0-7600-1098-6 McGee & Kramer: Concurrency State Models & Java Programs, Wiley & Sons, ISBN: 0-471-98710-7 Sedgewick, R.: Algorithms In C++, 3rd Edition, Addison Wesley, ISBN: 0-201-35088-2 Sun Microsystems: Java 2 Platform SE v. 1.4.1, URL: http://java.sun.com/j2se/1.4. 1/docs/api 17

A Test Det skal bemærkes, at der ikke vil blive udført en komplet whitebox-test, da dette projekt ikke er gruppens første programmeringsprojekt, og test dermed ikke har været det primære fokus i projektperioden. Denne whitebox-test skal betragtes som en udvidet blackbox-test, hvor det undersøges, om de forskellige metoder internt i klasserne håndterer forskellige typer data korrekt. Funktionalitet, der er identisk på tværs af versionerne af SearchCmdX vil kun blive beskrevet første gang den optræder. A.1 Whitebox-test af SearchCmd1 Vi nder det ikke nødvendigt at teste SearchCmd1, da vi ikke har været med til at udvikle den, og da SearchCmd2 i alle vigtige henseender i forbindelse med test er identisk med SearchCmd1. A.2 Whitebox-test af SearchCmd2 SearchCmd2 består af tre metoder, main(), readhtmllist() og exists() som vil blive testet separat. main() Denne metode giver args[0] videre til readhtmllist() som lnanvn, og det forventes, at hvis denne udeleades, returneres med en fejlmeddelelse. Hvis det indtastede lnavn ikke matcher en l på brugerens computer, kastes en FileNotFoundException. Det kan bekræftes, at dette er det faktiske uddata fra programmet. Det skal sikres, at den efterfølgende potentielt uendelige løkke, while(true) bliver termineret, altså at den betingelse der hedder if (name== name.length()==0) bliver opfyldt. Det forventes, at den bliver opfyldt, enten når der ikke er ere linier i len, eller når brugeren indtaster Return uden at indaste et søgeord. Ved kørsel af programmet på itcwww-small.txt og afprøvning af begge betingelser, kan det bekræftes, at dette er den faktiske opførsel. exists() Denne metode tager to argumenter, en HTMLlist-reference l og en Stringreference word. l refererer til den opbyggede liste, og word refererer til det søgeord, brugeren indtaster. Til sammen giver disse to parametre umiddelbart tre test-cases: 1. I det tilfælde, hvor l= og word er en given streng, forventes det, at løkken while (l!=) aldrig bliver kørt, og dermed at programmet afslutter med det samme. Dette uanset om strengen word ndes på nogle sider eller ej. Det kan bekræftes, at dette er tilfældet ved faktisk kørsel af programmet. 2. I det tilfælde, hvor l er en liste af HTMLlist-objekter og word er et ord, der ndes i listen forventes det, at den anden if-betingelse bliver opfyldt første gang, der stødes på ordet i l, og at adressen til siden, hvor dette ord står på bliver udskrevet. Dette afspejler det faktiske forløb ved kørsel af programmet. 3. Hvis l er en liste, og word ikke ndes i denne liste, vil betingelsen l.str.equals(word) aldrig blive opfyldt, og ordet aldrig udskrevet på skærmen. Dette stemmer overens med det faktiske output ved kørsel af programmet. 18

readhtmllist() Denne metode tager en String filename som argument, og som beskrevet under whitebox-testen af main() udskrives en fejlmeddelelse hvis filename ikke er initialiseret, og en FileNotFoundException hvis len ikke ndes på brugerens computer. Hvis len er på formen beskrevet i afsnit 2, læser kaldene til readline() en linie fra len indtil der ikke er ere, i hvilket fald der returneres. Dette bruges som termineringsbetingelse i løkken, while(true), og det kan bekræftes, at dette er det faktiske forløb ved kørsel af programmet. A.3 Whitebox-test af SearchCmd3 SearchCmd3 består af to metoder, buildlist() og main(), som vil blive testet separat. main() Løkken while (l!=) fungerer som søgemetode efter kaldet til buildlist() tidligere i metoden. Det forventes, at hvis der ikke er indtastet et lnavn og et søgeord, udskrives en fejlmeddelelse til skærmen, og programmet afslutter. Hvis der byttes om på disse to argumenter, eller der ikke ndes nogen l af det navn brugeren skriver, afslutter programmet med en FileNotFoundException. Det forventes, at metoden efterfølgende løber den vertikale liste igennem sekventielt, og hvis betingelsen if (l.str.equals(args[1])) bliver opfyldt, er det fordi søgeordet, brugeren har indtastet er blevet fundet. Er dette tilfældet, løbes den horisontale liste for det fundne element igennem på samme måde, og adresser udskrives til skærmen. Hvis listen ikke er initialiseret, forventes det, at programmer afslutter uden output. Det kan bekræftes, at det faktiske output stemmer overens med det forventede. buildlist() Den yderste while()-løkke sørger for at læse alle linierne i len, idet det forventes, at readline() returnerer, når der ikke er ere linier i len. Dette forventes også, at dette kald fejler med en FileNotFoundException, hvis len ikke eksisterer. Det kan bekræftes, at det forventede uddata er identisk med det faktiske uddata. Hvis inddata-len er på formen som beskrevet i afsnit 2, forudsættes og forventes det, at alle linier, der starter med * er PAGE-direktiver, som også indeholder en URL. Det bemærkes her, at hvis en linie er på mere end 12 tegn og starter med *, f.eks. en streng som MalformedURLException, vil den blive accepteret som en URL og indsat i URL-listen. Herefter forventes det, at løkken while (l!=) løber hele den vertikale liste igennem og sammenligner hvert element med det netop indlæste ord. Hvis de er ens, undersøges det om adressen på det sidst indsatte element i URL-listen er forskellig fra adressen for det netop indlæste ord, og hvis det er tilfældet, indsættes den nye adresse. Hvis programmet når til enden af listen og wordunique stadig er true, betyder det, det netop indlæste ord ikke er forekommet i den vertikale liste, hvorfor det indsættes dér. Ved afprøvning af denne del af programmet med en tom l, forventes det at programmet straks afsluttes, idet name==, samt at der ikke udskrives noget på skærmen. Det kan bekræftes, at dette er det faktiske output fra programmet i dette tilfælde. Da det netop indlæste ord, name sammenlignes med alle elementer i den vertikale liste, forventes det også, at der kun bliver indsat unikke ord i listen. Ved alle foretagne afprøvninger med de tre medfølgende dataler, kan det bekræftes, at dette er sket korrekt. Det samme gælder for adresser på ord, som allerede er indsat i den horisontale liste. Disse adresser er også unikke. A.4 Whitebox-test af SearchCmd4 SearchCmd4 har kun een metode, som det skønnes nødvendigt at teste, nemlig den er opbygger datastrukturen, buildhashtable(). 19

SearchCmd4 består, udover den samme datastruktur som i SearchCmd3, af en hashtabel, og det er primært rigtigheden af denne, som vil blive forsøgt vericeret i denne whitebox-test. buildhashtable() Visse elementer i denne metode er identiske med dem fra SearchCmd3, hvorfor tests af disse ikke vil blive beskrevet. Disse identiske dele omfatter løkken til at gennemlæse len, check på om der ordet starter med *PAGE samt gennemløb af ord-listen (før den vertikale, nu den horisontale, som per Figur 3). Før der indsættes elementer i hashtabellen, testes på, om L > 0.75, og hvis dette er tilfældet, oprettes en ny tabel der er dobbelt så stor som den oprindelige, og alle elementer i alle lister på alle pladser fra den gamle liste rehashes, modulo den nye tabels størrelse. Det forventes, at hvis nogle pladser i den gamle tabel er ubrugte, er hashtable[i]==, og disse springes over. Det bekræftes, at dette er programmets faktiske opførsel. Ydermere forventes det, at hvis det skulle ske, at hvis to elementer kolliderer ved rehashing til den nye tabel, sættes disse sammen i en hægtet liste. Dette er også programmets faktiske opførsel. Endelig forventes det, at referencen til den gamle hashtabel sættes til at pege på den nye hashtabel, som er dobbelt så stor. Dette vericeres ved videre kørsel af programmet, som viser, at referencevariablen hashtable rent faktisk peger på den nye hashtabel, newtable. I de tilfælde, hvor L < 0.75, beregnes hashværdien for det indlæste ord, og hvis den plads i arrayet, som ordet hasher til er tom (), indsættes det direkte. Dette sker ved at oprette et nyt HTMLlist-objekt med det indlæste ord som streng, og den nuværende side (CurrentPage) som argument til oprettelsen af et nyt URLs-objekt. Ifald pladsen i arrayet ikke er tom, løbes først den hægtede liste på denne plads igennem, og hvis ordet forekommer i forvejen, indsættes en reference til den side, hvorpå ordet står. Ved gentagne tests med opgbygninger og udskrivninger af opbyggede tabeller, bekræftes det, at dette er det faktiske forløb. B Uddata fra SearchCmd5 (Crawler) Siden http://www.w3.org linker til http://purl.org/dc Siden http://www.w3.org linker til http://www.w3.org/2000/08/w3c-synd/home.rss Siden http://www.w3.org linker til http://jigsaw.w3.org/css-validator/ Siden http://www.w3.org linker til http://validator.w3.org/ Siden http://www.w3.org linker til http://web.mit.edu/buildings/statacenter/ Siden http://www.w3.org linker til http://www.unicode.org/iuc/iuc23/ Siden http://www.w3.org linker til http://www.w3.org/international/ Siden http://www.w3.org linker til http://www.google.com Siden http://www.w3.org linker til http://lists.w3.org/archives/public/w3c-announce/ Siden http://www.w3.org linker til http://cgi.w3.org/memberaccess/accessrequest Siden http://www.w3.org linker til http://lists.w3.org/archives/public/site-comments/ Siden http://www.w3.org linker til http://purl.org/rss/1.0/ Siden http://www.w3.org linker til http://validator.w3.org/ 20

Siden http://www.w3.org linker til http://jigsaw.w3.org/css-validator/ (Udskriver crawler data...) 15:35:44 http://www.w3.org with http://jigsaw.w3.org/css-validator/ http://www.w3.org Contents http://www.w3.org for http://www.w3.org color: http://www.w3.org statements. http://www.w3.org physical, http://www.w3.org Multimodal http://www.w3.org P3P http://www.w3.org rich, http://www.w3.org return http://www.w3.org updated. http://www.w3.org news http://www.w3.org not http://www.w3.org mathematical http://www.w3.org users. http://www.w3.org systems http://www.w3.org CSS http://jigsaw.w3.org/css-validator/ http://www.w3.org Messaging http://www.w3.org source http://jigsaw.w3.org/css-validator/ User http://www.w3.org Comments http://www.w3.org C Kildekode til SearchCmd1 import java.io.*; class HTMLlist String str; HTMLlist next; 21

HTMLlist(String s, HTMLlist n) str=s; next=n; class Searcher static long ordlisteobj=0, ordstrengobj=0; public static boolean exists(htmllist l, String word) long time=system.currenttimemillis(); while(l!=) if (l.str.equals(word)) System.out.println(System.currentTimeMillis()-time); return true; l = l.next; return false; public static HTMLlist readhtmllist(string filename) throws IOException String name; HTMLlist start,current,tmp; BufferedReader infile = new BufferedReader(new FileReader(filename)); name=infile.readline(); start=new HTMLlist(name,); current=start; while(true) name = infile.readline(); if(name==) break; tmp=new HTMLlist(name,); current.next=tmp; current=tmp; infile.close(); return start; ; public class SearchCmd1 public static void main(string[] args) throws IOException String name; long time=system.currenttimemillis(); HTMLlist l=searcher.readhtmllist(args[0]); System.out.println(System.currentTimeMillis()-time); BufferedReader inuser = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Afslut med retur uden indtastning"); while(true) System.out.print("Soeg efter: "); name=inuser.readline(); time=system.currenttimemillis(); if(name== name.length()==0) break; 22

if(searcher.exists(l, name)) System.out.println("Ordet "+name+" findes."); else System.out.println("Ordet "+name+" findes IKKE."); System.out.println(System.currentTimeMillis()-time); D Kildekode til SearchCmd2 import java.io.*; import java.lang.*; class HTMLlist String str; HTMLlist next; HTMLlist(String s, HTMLlist n) str=s; next=n; class Searcher public static void exists(htmllist l, String word) String CurrentPage = ""; //Saa en adresse kun udskrives een gang boolean wordfound = false; while(l!=) if (!l.str.equals("") && l.str.substring(0,1).equals("*")) wordfound = false; CurrentPage = l.str.substring(6); if (l.str.equals(word) && wordfound == false) System.out.println(CurrentPage); wordfound = true; l = l.next; public static HTMLlist readhtmllist(string filename) throws IOException String name; HTMLlist start,current,tmp; BufferedReader infile = new BufferedReader(new FileReader(filename)); name=infile.readline(); 23

start=new HTMLlist(name,); current=start; while(true) name = infile.readline(); if(name==) break; tmp=new HTMLlist(name,); current.next=tmp; current=tmp; infile.close(); return start; public class SearchCmd2 public static void main(string[] args) throws IOException String name; HTMLlist l=searcher.readhtmllist(args[0]); BufferedReader inuser = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Afslut med retur uden indtastning"); while(true) System.out.print("Soeg efter: "); name=inuser.readline(); if (name== name.length()==0) break; System.out.println("Ordet "+name+" findes paa disse sider:"); Searcher.exists(l, name); E Kildekode til SearchCmd3 import java.io.*; import java.lang.*; class URLs String Address; URLs next; URLs(String url, URLs n) Address = url; next = n; class HTMLlist 24

String str; URLs URLList; HTMLlist next; HTMLlist(String s, HTMLlist n) str=s; next=n; class ListBuilder static long numofuniquewords=0, uniquewordsbytes=0, uniqueurlsbytes=0; static long numofuniqueurls=0, uniqueurlstrings=0; public static HTMLlist buildlist(string filename) throws IOException //name og CurrentPage bruges vertikalt //URLPage og line bruges horisontalt String name, CurrentPage = ""; URLs tmpurl=; boolean wordunique = true; HTMLlist start, list, tmphtml; BufferedReader infile = new BufferedReader(new FileReader(filename)); start = ; while((name = infile.readline())!= ) // Check, om der er tale om et *PAGE-direktiv if (!name.equals("") && name.substring(0,1).equals("*")) // Dette check fanger ikke linier som fx "***MALFORMEDURL"... if (name.length()<12) System.out.println("Possibly malformed URL ==> "+name+ " <==. Please try again."); return ; CurrentPage = name.substring(6); uniqueurlstrings++; uniqueurlsbytes+=currentpage.length(); name = infile.readline(); list = start; wordunique=true; while(list!=) if (list.str.equals(name)) wordunique = false; if (list.urllist == list.urllist.address!=currentpage) numofuniqueurls++; tmpurl = new URLs(CurrentPage, list.urllist); list.urllist = tmpurl; 25