ΕΡΓΑΣΙΑ 4 «Μηχανή Αναζήτησης Αρχείων» Ημερομηνία Παράδοσης: 30/04/2015, 09:00 π.μ. Στόχος Στόχος της Εργασίας 4 είναι να η εξοικείωση με την αντικειμενοστρέφεια (object oriented programming). Πιο συγκεκριμένα, καλείστε να δημιουργήσετε κάποιες νέες κλάσεις, με δεδομένα χαρακτηριστικά και μεθόδους. Περιγραφή Αναντίλεκτα, το μέγεθος του διαδικτύου είναι τεράστιο και αυξάνει με εκπληκτικούς ρυθμούς. Υπό αυτές τις συνθήκες, η εύρεση πληροφοριών αποτελεί μία εξαιρετικά δύσκολη υπόθεση, που θα παρέμενε δύσκολη εάν δεν υπήρχαν εργαλεία όπως οι μηχανές αναζήτησης. Οι μηχανές αναζήτησης είναι από τα λίγα εργαλεία του διαδικτύου που προσπαθούν να βάλουν τάξη και να προσφέρουν διέξοδο σε όσους αναζητούν μία πληροφορία μέσα στο αχανές σύνολο των πληροφοριών αλλά δεν γνωρίζουν πού ακριβώς θα την βρουν. Η απλούστερη αναζήτηση στοιχείων γίνεται με τις λέξεις-κλειδιά που δίνει ο χρήστης και η μηχανή αναζήτησης του παρουσιάζει τα αρχεία εκείνα (κείμενο, εικόνες, κτλ) στα οποία μπορεί αυτός να βρει σχετικές πληροφορίες. Η μηχανές αναζήτησης δεν είναι απλά συστήματα. Περιλαμβάνουν διάφορα προγράμματα και μεθοδολογίες που αλλάζουν συνέχεια. Η κάθε μηχανή αναζήτησης έχει το δικό της τρόπο συλλογής, αποθήκευσης και παρουσίας των αποτελεσμάτων, άλλα σε γενικές γραμμές τα προγράμματα που αποτελούν μια μηχανή αναζήτησης είναι: Ιχνηλάτης Ιστού (Web Crawler) : Ο web crawler είναι ένα λογισμικό, το οποίο περιηγείται στο διαδίκτυο, με ένα αυτόματο και μεθοδικό τρόπο κι έχει ως σκοπό την ανακάλυψη, ανάκτηση και αποθήκευση νέου περιεχομένου. Αποθετήριο σελίδων (Page Repository) : Κρατά αποθηκευμένο το περιεχόμενο που ανακτάται από τον ιστό μέσω του ιχνηλάτη, για περαιτέρω επεξεργασία. Ευρετηριοποιητής (Indexer) : Η ευρετηριοποίηση είναι μια μέθοδος για την κατηγοριοποίηση του περιεχομένου που έχει ανακτηθεί, έτσι ώστε η αναζήτηση στο περιεχόμενο αυτό να γίνεται με τρόπο γρήγορο και αποδοτικό. Φόρμα αναζήτησης με βάση λέξεις κλειδιά (Search Form) : Βασικό στοιχείο μιας μηχανής αναζήτησης είναι η αλληλεπίδραση της με το χρήστη. Η αλληλεπίδραση αυτή γίνεται συνήθως με μια φόρμα αναζήτησης (search form), στην οποία ο χρήστης έχει τη δυνατότητα εισαγωγής λέξεων/φράσεων. Μηχανή επερωτήσεων (Query Engine) : Η μηχανή επερωτήσεων είναι υπεύθυνη για την παραλαβή των δεδομένων που δίνει ο χρήστης στη φόρμα αναζήτησης και την εκτέλεση επερωτήσεων. Στο διαδίκτυο υπάρχουν αρκετές μηχανές αναζήτησης, οι οποίες τις περισσότερες φορές ξεκίνησαν από πειραματικά ερευνητικά προγράμματα (projects) και εξελίχθηκαν σε ολόκληρες εταιρείες, ενώ από πλευράς χρήσης εξυπηρετούν εκατομμύρια χρήστες καθημερινά. Ενδεικτικά αναφέρονται εδώ οι πιο γνωστές από αυτές, όπως είναι το Google, το Bing, η Yahoo, κ.ά. 1
Στην άσκηση αυτή θα υλοποιήσετε μια μικρής κλίμακας μηχανή αναζήτησης λέξεων σε αρχεία που είναι αποθηκευμένα στον υπολογιστή σας. Κατά συνέπεια, το πρόγραμμά σας θα περιέχει τα βασικά υποσυστήματα μιας μηχανής αναζήτησης που περιγράφηκαν πιο πάνω, εκτός από τον web crawler. Υλοποίηση Η αρχιτεκτονική του συστήματος που καλείστε να υλοποιήσετε φαίνεται πιο κάτω: Search Form Query Engine Page Repository Indexer Pages Σχήμα 1: Αρχιτεκτονική Συστήματος Στο πρώτο βήμα, ο χρήστης θα δίνει στη γραμμή αναζήτησης (search form) τη λέξη (ένα string χωρίς κενά) που θέλει να αναζητήσει. Το ερώτημα θα στέλνεται στη μηχανή επερωτήσεων (Query Engine) που θα βρίσκει από τον Indexer ποια αρχεία περιέχουν τη λέξη κλειδί. Στη συνέχεια, ανακτώνται από το αποθετήριο αρχείων (Page Repository) τα περιεχόμενα των αρχείων (Page) που περιέχουν την προς αναζήτηση λέξη-κλειδί και θα παρουσιάζονται στον χρήστη. Η μηχανή επερωτήσεων θα αναλαμβάνει να βρει και να παρουσιάσει επίσης τα αρχεία που είναι σχετικά με τη λέξη κλειδί. Πιο λεπτομερής περιγραφή δίνεται πιο κάτω. Σας δίνεται το αρχείο exercise4.zip που περιέχει το σκελετό των κλάσεων που πρέπει να υλοποιήσετε. Εσείς θα πρέπει να συμπληρώσετε ότι ζητείτε, προσθέτοντας επιπλέον μεθόδους αν επιθυμείτε. Επίσης μέσα το zip file περιέχει κάποια αρχεία.txt. Αποσυμπιέστε το αρχείο.zip και τοποθετήστε τα αρχεία μέσα στο Project σας στο Eclipse. Όταν ο χρήστης δίδει μια λέξη, θα γίνεται αναζήτηση μέσα στα δοθέντα txt αρχεία. Μπορείτε να προσθέσετε και άλλα txt αρχεία αν θέλετε. Το πρόγραμμα σας θα υλοποιεί 5 κλάσεις που παρουσιάζονται αναλυτικά πιο κάτω. Στα δοθέντα αρχεία των κλάσεων Page και PageRepository, υπάρχει από μια μέθοδος main. Καθώς υλοποιείτε την καθεμιά από αυτές τις κλάσεις, μπορείτε να τις δοκιμάζετε αν δουλεύουν σωστά μέσω της αντίστοιχης δικής τους main. Το τελικό πρόγραμμα θα τρέχει μέσω της μεθόδου main που βρίσκεται μέσα στην κλάση SearchForm. 1) Κλάση Page : Κάθε αντικείμενο της κλάσης αυτής θα κρατά πληροφορίες (όνομα αρχείου, περιεχόμενο) για ένα αρχείο. Άρα τα χαρακτηριστικά της κλάσης είναι το όνομα του αρχείου (filename) και το περιεχόμενο του αρχείου (content). Ο κατασκευαστής της κλάσης δέχεται σαν είσοδο το όνομα του αρχείου και το ανοίγει για διάβασμα. Στη συνέχεια θα καλεί τη μέθοδο load για να διαβάσει το περιεχόμενο του αρχείου και θα το αποθηκεύει στη μεταβλητή content. Μετά την ανάγνωση του περιεχομένου του αρχείου, θα καλείται η μέθοδος removespecialchars (δίνεται) για να αφαιρέσει από τη μεταβλητή content ειδικούς χαρακτήρες και αριθμούς, να 2
μετατρέψει κεφαλαία σε μικρά, αφήνοντας μόνο χαρακτήρες από a-z. Η κλάση συμπληρώνεται με μεθόδους που επιστρέφουν το όνομα του αρχείου (getfilename) και το περιεχόμενο του αρχείου (getcontent). 2) Κλάση PageRepository : Η κλάση αυτή έχει σαν χαρακτηριστικά ένα πίνακα τύπου Page (για να αποθηκεύει αντικείμενα τύπου Page) και μια σταθερά που δηλώνει τον αριθμό των αρχείων που θα διαχειρίζεται. Δηλώστε τη σταθερά ίση με τον αριθμό των αρχείων.txt που σας δίνεται στο αρχείο pages.zip. O κατασκευαστής θα αρχικοποιεί τον πίνακα με αντικείμενα τύπου Page όπου το κάθε αντικείμενο θα αντιστοιχεί σε ένα αρχείο.txt από τα δοθέντα αρχεία. Θα βρείτε αναγκαία τη δημιουργία μεθόδων που να επιστρέφουν (α) τον αριθμό των αρχείων που διαχειρίζεται η κλάση (getnumofpages), (β) το όνομα κάποιου αρχείου (getpagefilename), (γ) πίνακα με όλα τα ονόματα όλων των αρχείων (getallpagefilenames), (δ) το περιεχόμενο κάποιου αρχείου (getpagecontent) κτλ. Κάποιες από αυτές δίνονται. 3) Κλάση Indexer : Η κλάση αυτή θα επικοινωνεί με την κλάση PageRepository για να δημιουργήσει το ευρετήριο (index). Πιο συγκεκριμένα, τα χαρακτηριστικά της κλάσης αυτής θα είναι (α) ένα αντικείμενο της κλάσης PageRepository, (β) ένας πίνακας words που θα τοποθετηθούν μέσα όλες οι λέξεις των αρχείων κειμένου (μια φορά η κάθε λέξη) που διαχειρίζεται το αποθετήριο (PageRepository), (γ) ένας πίνακας δύο διαστάσεων index που θα περιέχει τα αρχεία (1 ή περισσότερα) στα οποία υπάρχει η κάθε λέξη του πίνακα words, και (δ) ο αριθμός των λέξεων (numofwords) που υπάρχουν στον πίνακα words. Το αρχικό μέγεθος του πίνακα words θα λαμβάνεται από τη σταθερά MAX_WORDS (δίνεται). Για παράδειγμα, αν έχουμε: words[5] = in index[5][0] = test.txt index[5][1] = test1.txt index[5][2] = test2.txt σημαίνει ότι η λέξη in υπάρχει μέσα στα αρχεία test.txt, text1.txt και test2.txt. Ο κατασκευαστής της κλάσης θα δέχεται σαν είσοδο ένα αντικείμενο τύπου PageRepository και θα δημιουργεί τους 2 πίνακες. Επίσης, θα αρχικοποιεί και την κάθε θέση του πίνακα δύο διαστάσεων index με το κενό. Η κλάση θα υλοποιεί τη μέθοδο createindex που θα ανακτά τα περιεχόμενα όλων των αρχείων που διαχειρίζεται η κλάση PageRepository και θα «γεμίζει» τους πίνακες words και index. Επίσης θα βρείτε αναγκαίο να υλοποιήσετε τη μέθοδο getindexfilenames που επιστρέφει πίνακα με όλα τα ονόματα αρχείων που περιέχουν μια συγκεκριμένη λέξη. 4) Κλάση SearchForm : Όπως φαίνεται στο σχήμα 1, η κλάση αυτή (που δίνεται εξ ολοκλήρου) επικοινωνεί μόνο με την κλάση QueryEngine. Θα υλοποιεί μόνο τη μέθοδο main. Η μέθοδος main θα δημιουργεί ένα αντικείμενο της κλάσης QueryEngine και θα ζητά από το χρήστη μια λέξη κλειδί. Όταν ο χρήστης δώσει τη λέξη κλειδί, θα καλούνται 2 συναρτήσεις της κλάσης QueryEngine για να φέρουν (α) τα ονόματα και τα περιεχόμενα των αρχείων που περιέχουν τη λέξη αλλά και (β) τα ονόματα των αρχείων που είναι σχετικά με την προς αναζήτηση λέξη. 5) Κλάση QueryEngine : Όπως φαίνεται στο σχήμα 1, η κλάση αυτή συνδέεται τόσο με την κλάση Indexer, όσο και με την κλάση PageRepository. Τα χαρακτηριστικά της θα είναι ένα αντικείμενο τύπου PageRepository και ένα αντικείμενο τύπου Indexer που θα δημιουργούνται στον κατασκευαστή της κλάσης. Μετά τη δημιουργία του αντικειμένου Indexer, θα καλείται η μέθοδος createindex για να δημιουργηθεί το ευρετήριο. Η κλάση αυτή θα υλοποιεί 3 τουλάχιστον μεθόδους: a. exactmatching : Λαμβάνει σαν είσοδο ένα String (τη λέξη που εισήγαγε ο χρήστης) και βρίσκει (μέσω της κλάσης indexer) τα ονόματα αρχείων που περιέχουν τη λέξη και τα περιεχόμενά των αρχείων αυτών (από το repository) 3
και τα επιστρέφει όλα μαζί σαν ένα String στη μορφή: X file(s) found:\n<όνομα αρχείου1>\n<περιεχόμενο αρχείου1>\n<όνομα αρχείου2>\n<περιεχόμενο αρχείου2>\n όπου Χ είναι ο αριθμός των αρχείων στα οποία βρέθηκε η λέξη. Αν δεν βρεθεί κανένα αρχείο, η μέθοδος να επιστρέφει το string No files found\n. b. substringmatching : Λαμβάνει σαν είσοδο ένα String (τη λέξη που εισήγαγε ο χρήστης) και βρίσκει πόσο σχετικά (relevant) με τη λέξη είναι τα αρχεία που δεν περιέχουν τη λέξη. Ο βαθμός σχετικότητάς (relevance) τους θα προκύψει από τον αλγόριθμο lcss (longest common subsequence) που περιγράφεται πιο κάτω. Η μέθοδος θα επιστρέφει ένα String με τα ονόματα των αρχείων αυτών και δίπλα το βαθμό σχετικότητάς τους με τη λέξη που έδωσε ο χρήστης, ταξινομημένα από το πιο σχετικό στο λιγότερο σχετικό στη μορφή: <όνομα αρχείου1> - <βαθμός σχετικότητας αρχείου1>\n<όνομα αρχείου2> - < βαθμός σχετικότητας αρχείου2>\n c. lcss : Αναδρομική συνάρτηση που παίρνει σαν είσοδο 2 Strings (α) το περιεχόμενο ενός αρχείου και (β) τη λέξη που εισήγαγε ο χρήστης, και βρίσκει το βαθμό σχετικότητάς τους. Προτού αναφερθούμε στην τεχνική αυτή, αξίζει να δούμε τη διαφορά μεταξύ μιας συμβολοσειράς (string), μιας υποσυμβολοσειράς (substring) και μιας υποακολουθίας (subsequence). Δείτε το πιο κάτω παράδειγμα (όπου διακρίνονται με διαφορετικά χρώματα οι επί μέρους έννοιες): Συμβολοσειρά: CGATAATTGAGA Υποσυμβολοσειρά (συνεχής): CGA Υποακολουθία (όχι κατ ανάγκη συνεχής): AAGAA Ένας από τους πιο γνωστούς αλγόριθμους εύρεσης ομοιότητας είναι ο αλγόριθμος LCSS. Ο αλγόριθμος αυτός χρησιμοποιείται ευρύτατα στην αναζήτηση ομοιότητας κειμένου. Δεδομένων 2 ακολουθιών Α και Β, ο αλγόριθμος LCSS βρίσκει τη μέγιστη κοινή υπό-ακολουθία τους. Ο αναδρομικός τύπος που δίνει το μήκος της μέγιστης υπο-ακολουθίας κατά LCSS μεταξύ δύο συμβολοσειρών είναι: 0 LCSS ( A, B) 1 LCSS( A), B)) max( LCSS( A), B), LCSS( A, B)) Head Tail A={ 1 1 1 2 2 3 6 8 9 6 } B={ 1 1 1 2 2 2 3 6 8 9 }, Εάν A ή B είναι κενά, Εάν Head(A)=Head(B), αλλιώς Οι γραμμές σύνδεσης παρουσιάζουν μια ενδεχόμενη (από πολλές) LCSS λύση: LCSS(A,B) = 9 Εξίσωση (1) Ο αναδρομικός τύπος της Εξίσωσης 1 δίνει το μήκος της μέγιστης υπόακολουθίας μεταξύ 2 ακολουθιών Α και Β, όπου Head(A) είναι ο πρώτος χαρακτήρας της συμβολοσειράς A, ενώ A) είναι η υποσυμβολοσειρά του Α από το 2 ο χαρακτήρα έως και το τέλος. Η συνάρτηση αυτή, λόγω της αναδρομικής της φύσης είναι πολύ αργή όταν εκτελεστεί σε μεγάλου μεγέθους λέξη δοθείσα από το χρήστη. 4
Παράδοση 1. Όταν έχετε τελειώσει με τον πηγαίο κώδικα, μεταγλωττίστε το και βεβαιωθείτε ότι τρέχει σωστά. 2. Παραδώστε ένα zip file που να περιέχει μόνο τα.java αρχεία σας ηλεκτρονικά μέσω του submit assignment (κάτω από το Ασκήσεις Εργασία 4 στην ιστοσελίδα του μαθήματος μέχρι τις 30/04/2015 και ώρα 09:00 π.μ.. Το zip file να έχει όνομα userid_erg4.zip. 3. Μέσα στο zip file μαζί με τα αρχεία πηγαίου κώδικα, παραδώστε και την λίστα δοκιμής, (userid _erg4.txt) με τα παραδείγματα εκτέλεσης (δείτε τελευταία σελίδα). 4. Προσοχή: Το σύστημα ελέγχει το χρόνο παράδοσης εργασιών γι αυτό μην περιμένετε την τελευταία στιγμή να κάνετε submit την εργασία σας. a. Όπου userid βάλτε το username που σας δόθηκε από το τμήμα. b. η λίστα δοκιμής μπορεί να δημιουργηθεί αν τρέξετε το πρόγραμμά σας από την γραμμή εντολών (terminal) και χρησιμοποιώντας την εντολή script που περιγράφεται στο πρώτο εργαστήριο (φυλλάδιο Unix). 5. Στα εργαστήρια (30/04/2015) θα πρέπει να παραδώσετε σε χαρτί τον πηγαίο κώδικα και την λίστα δοκιμής συνδεδεμένα μαζί. Ο κώδικας που θα αποστείλετε ηλεκτρονικά και ο κώδικας που θα παραδώσετε σε χαρτί πρέπει να είναι ακριβώς ο ίδιος. Σε αντίθετη περίπτωση παίρνετε αυτόματα βαθμολογία 0. Βαθμολογία: Σημαντικό μέρος της αξιολόγησης θα αποτελέσει η ταχύτητα εκτέλεσης του προγράμματος. Επίσης, ένα πρόγραμμα για να πάρει όλες τις μονάδες είναι απαραίτητο να: 1. χρησιμοποιεί σχόλια 2. ευθυγραμμισμένος κώδικας 3. αυτό-επεξηγηματικά ονόματα για τις μεταβλητές 4. Αρχές δομημένου προγραμματισμού με αποδοτική χρήση μεθόδων Για όλα τα παραπάνω ακολουθήστε τις οδηγίες που περιγράφονται εδώ: http://introcs.cs.princeton.edu/java/11style/ Τα αρχεία με το πηγαίο κώδικα πρέπει οπωσδήποτε να περιέχουν μια συμπληρωμένη κατάλληλα επικεφαλίδα από σχόλια στην αρχή του αρχείου όπως: /** * Author: Γράψτε εδώ το όνομα σας * Written:../../2015 * Last updated:../../2015 * * Γράψτε εδώ πληροφορίες σχετικά με το τι κάνει * το πρόγραμμα * */ ΠΡΟΣΟΧΗ Κώδικας που δε μεταγλωττίζει ή δεν τρέχει (crashes) παίρνει αυτόματα βαθμολογία 0. Ανίχνευση αντιγραφής οδηγεί σε μηδενισμό για όλους τους εμπλεκόμενους. Παραδείγματα Εκτέλεσης (με κόκκινο η είσοδος του χρήστη) στις επόμενες σελίδες 5
1 ο Παράδειγμα Search: web 1 file(s) found: test.txt test2.txt (3) test3.txt (3) 2 ο Παράδειγμα Search: that 2 file(s) found: test.txt test2.txt test3.txt (4) 3 ο Παράδειγμα (μικρή καθυστέρηση για εξαγωγή αποτελέσματος) Search: apache 1 file(s) found: test2.txt test.txt (6) test3.txt (6) 4 ο Παράδειγμα (μεγαλύτερη καθυστέρηση για εξαγωγή αποτελέσματος) Search: wwwww No files found! test.txt (5) test2.txt (5) test3.txt (3) 6