EKSPLORACJA ZASOBÓW INTERNETU LAB IX - APACHE TIKA 1. Motywacja  większość programów rozumie tylko dedykowane im formaty plików  Microsoft Offiice – format Office Open XML, OpenOffice.org – format OpenDocument – formy XML- owe, ale programy potrzebują specjalnych konwerterów, aby rozumieć format dedykowany innemu programowi

Cel:  aplikacja, która rozumie i przetwarza większość powszechnie używanych formatów plików  wyszukiwarka, która przetwarza dokumenty na dzielonym dysku sieciowym: arkusze Excel, dokumenty Word oraz PDF, pliki tekstowe, obrazy i pliki dźwiękowe w różnych formatach, prezentacje PowerPoint, pliki OpenOffice, HTML, archiwum Zip  dla każdego z tych formatów posiadasz dedykowany program, ale nie chcesz dla tysięcy plików otwierać go i ręcznie kopiować/wklejać go do wyszukiwarki w celu zindeksowania

2. Typy plików:  w sieci istnieje ok. 51 tysięcy różnych typów plików. Zawartość różni się pod względem rozmiaru, formatu i kodowania  metoda przechowywania tekstu i informacji  “spreadsheet”, “web page” - nie wystarczająco dokładne; “.xls”, “.html” - bardzo często zależy od systemu operacyjnego oraz zainstalowanych programów;  MIME - Multipurpose Internet Mail Extensions – aby ułatwić programom “deal with the data in an appropriate manner”  identyfikator: type/subtype oraz opcjonalne parametry attribute=value  ponad 1000 typów oficjalnych: text/plain; charset=us-ascii, text/html, image/jpeg, application/msword, kilka tysięcy typów nieoficjalnych: image/x-icon and application/vnd.amazon.ebook  ze strony programistów: konieczność uwzględnienia wiedzy nt. formatu w aplikacji  Tika udostępnia metody automatycznego wykrywania typu pliku

3. Biblioteki do parsowania  Microsoft Office – czytanie i pisanie dokumentów Word, Adobe Acrobat oraz Acrobat Reader – to samo dla dokumentów PDF  interakcja z użytkownikiem, brak dostępu do zawartości dla innych programów  alternatywa: biblioteka parsująca – format dokumentu mapowany na API, którego łatwiej używać i zrozumieć niż surowe wzorce bajtów  np. zamiast odnosić się do sum kontrolnych CRC, metod kompresji, itp. wykorzystanie pakietu java.util zip pozwala na wykorzystanie ZipFile and ZipEntry

public static void listZipEntries(String path) throws IOException { ZipFile zip = new ZipFile(path); for (ZipEntry entry : Collections.list(zip.entries())) { System.out.println(entry.getName()); } }

 w Javie i innych językach istnieje wiele bibliotek dla plików tekstowych, XML, różnych formatów obrazów, plików audio, video;  większość typów plików nie jest wspierana lub API są zaprojektowane z myślą o konkretnych zastosowaniach (brak uniwersalności)  biblioteki Apache PDFBox (http://pdfbox.apache.org/) oraz POI (http://poi.apache.org/) implementują wsparcie dla plików PDF oraz Microsoft Office  samodzielne napisanie programu, który korzysta z kilku takich bibliotek byłoby trudne  potrzeba ogólnego API do parsowania różnych typów dokumentów (“universal language of digital documents”)

4. Ustrukturalizowany tekst jako uniwersalny język  większość interesujących informacji w dokumentach cyfrowych ma charakter tekstowy i liczbowy  tekst – najmniejszy wspólny mianownik jako abstrakcja dokumentu  linki pomiędzy dokumentami, akapity, nagłówki, pogrubione frazy  XML oraz HTML – formaty, które umożliwiają strukturalne adnotacje oraz łatwy dostęp do prostego tekstu (XML – dobrze zdefiniowany, łatwy do przetwarzania; HTML – zbiór elementów, które niemal każdy rozumie),  Tika wykorzystuje XHTML do reprezentacji ustrukturalizowanych dokumentów

5. Metadane  “dane nt. danych” - zajmują mało miejsca  podjęcie decyzji co do sposobu analizy  standard Dublin Core – 15 atrybutów (format danych, tytuł, temat, twórca, itd.)  wiele aplikacji tworzy swoje formaty metadanych: Adobe - Extensible Metadata Platform (XMP) – obok elementów z Dublin Core, cechy specyficzne dla plików Photshopa, Word Metadata – specyficzne dla .doc, .ppt, itd.  Tika oferuje wsparcie dla najpopularniejszych istniejących formatów oraz możliwość definiowania własnych formatów

 identyfikacja typu pliku  wybór odpowiedniego parsera (np. PDFBox dla plików PDF)  wydobycie zawartości tekstowej (np. wyszukiwanie) oraz metadanych (np. wykrycie, czy plik jest locked)  identyfikacja języka (czy występuje konieczność przetłumaczenia) 7. Apache Tika toolkit do wykrywania oraz wydobywania metadanych oraz ustrukturalizowanej zawartości tekstowej z różnych dokumentów z wykorzystaniem (istniejących) bibliotek.  2007 – ,  2008 – podprojekt Lucene,  2010 – Top-level Project (TLP)  2011 – wypuszczono wersję 1.0, obecnie wersja 1.14  http://tika.apache.org

Podstawowe cele:  Ujednolicone parsowanie: zbiór funkcji oraz interface Javy, który pozwoli na wykorzystanie różnorodnych bibliotek parsujących: org.apache.tika.Parser  Integracja parserów: łatwy dostęp do bibliotek parsowania różnych formatów, a nie tworzenie nowych  Niskie wymagania pamięciowe: czytanie przyrostowe z wykorzystaniem SAX-based XHTML events; SAX = the Simple API for XML processing; tradycyjnie - parsowanie XML z wykorzystaniem Document Object Model (DOM) - ładuje cały dokument XML do pamięci i udostępnia poprzez API; SAX – parsowanie przyrostowe, ale trzeba być świadomym stanu (wiele tagów) – konieczność zaimplementowania funkcji startDocument, startElement, itd. Tika adaptuje model SAX, umożliwiając określenie, które tagi powinny zostać przetworzone/pominięte  Szybkość przetwarzania i odpowiedzi co do typu pliku  Baza danych oraz wykrywanie MIME  Elastyczność względem formatów metadanych: rozumienie różnych modeli metadanych  Wykrywanie języka Główne zastosowania:  indeksowanie zawartości tekstowej dokumentów o różnorodnych typach  analiza dokumentów – znalezienie kluczowych pojęć: ludzi, miejsce, relacji między nimi z tekstu; Apache UIMA oraz Mahout  Digital Asset Management – kateogoryzacja typów, bogate metadane, łatwe wyszukiwanie Tika jest dostępna w postaci programu z GUI i poleceń wydawanych z linii komend

8. Fasada Tika  analogia z brokerem inwestycyjnym: wymiana pieniędzy i wysokopoziomowa specyfikacja strategii inwestycyjnej  kilka linii kodu – aplikacja, która rozumie i przetwarza dziesiątki różnych formatów plików import java.io.File; import org.apache.tika.Tika; public class SimpleTextExtractor { public static void main(String[] args) throws Exception { // Create a Tika instance with the default configuration Tika tika = new Tika(); // Parse all given files and print out the extracted text content for (String file : args) { String text = tika.parseToString(new File(file)); System.out.print(text); } } }

 parseToString() - zwraca zawartość tekstową jako string; długość ograniczona domyślnie  parse() - zwraca obiekt klasy java.io. Reader, który pozwala na przyrostowe czytanie dokumentu  detect() - wykrycie typu pliku

9. Organizacja pakietów tika-core: fasada Tika, klasy dla rozpoznania typu MIME (org.apache.tika.mime), interface Parser (org.apache.tika.parser), który jest rozszerzany i implementowany przez Parsers w tika-parsers; interface wykrywania języka (org.apache.tika.language), struktury metadanych (org.apache.tika.metadata), metody dostępu do ustrukturalizowanego tekstu (org.apache.tika.sax) tika-parsers: klasy i funkcjonalność pozwalająca korzystać z bibliotek parsujących tika-app: dostęp do poleceń z linii komend oraz GUI tika-bundle: OSGI

10. Wykrywanie typu pliku  wewnętrzna baza  Java API dla interakcji z bazą i wykorzystania różnych metod wykrywania typu pliku Tika wykorzystuje informacje nt.:  rozszerzeń plików,  content type (brak nazwy i rozszerzenia, np. w bazie danych, nagłówek Content-Type w HTML albo podczas zachowywania przez Microsoft Word),  magic bytes (prefiks, np. GIF - GIF87a lub GIF89a; klasy Java - CA FE BA BE (hex));  kodowania znaków – parametr charset często nie jest poprawny (BOM – byte order mark – kilka pierwszych bajtów dokumentu),  częstotliwości znaków (prosty tekst?); metody statystyczne (znaki charakterystyczne dla danego języka);  inne mechanizmy (np. dla XML parsowany jest root element) import java.io.File; import org.apache.tika.Tika; public class SimpleTypeDetector { public static void main(String[] args) throws Exception { Tika tika = new Tika(); for (String file : args) { String type = tika.detect(new File(file)); System.out.println(file + ": " + type); } } }

MediaType type = MediaType.parse("text/plain; charset=UTF-8"); System.out.println("type: " + type.getType()); System.out.println("subtype: " + type.getSubtype()); Map parameters = type.getParameters(); System.out.println("parameters:"); for (String name : parameters.keySet()) { System.out.println(" " + name + "=" + parameters.get(name)); } 11. Wydobycie zawartości File document = new File("example.doc"); String content = new Tika().parseToString(document); System.out.print(content);

1. Tika wykorzystuje heurystyki do określenia pliku: w przykładzie zaczyna się od %PDF-, a więc application/pdf 2. Wybór parsera odpowiadającego typowi dokumentu: org.apache.tika.parser.pdf.PDFParser 3. Dokument jest przekazywany do parsera: klasa PDFParser to wraper dla bardzo zaawansowanej biblioteki Apache PDFBox – konwertuje metadane oraz zawartość tesktową do formatu zdefiniowanego przez Tika, w przypadku błędu: TikaException, jeśli dokument nie pasuje do reguł przetwarzania danego formatu lub IOException jeśli dokument nie może być przeczytany. Limit metody parseToString to 100 000 znaków, reszta zignorowana. Tika nie zawiera daje indeksowania/ wyszukiwania. Istnieje konieczność jej połączenia z Lucene. import java.io.File; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.Field.Index; import org.apache.lucene.document.Field.Store; import org.apache.lucene.index.IndexWriter; import org.apache.tika.Tika; public class LuceneIndexer { //Facade instance for full text extraction private final Tika tika; // Lucene index writer for indexing extracted text private final IndexWriter writer; // Create Lucene indexer instance public LuceneIndexer(Tika tika, IndexWriter writer) { this.tika = tika; this.writer = writer; } // Add file to index public void indexDocument(File file) throws Exception { Document document = new Document(); document.add(new Field("filename", file.getName(), Store.YES, Index.ANALYZED)); document.add(new Field( "fulltext", tika.parseToString(file), Store.NO, Index.ANALYZED)); writer.addDocument(document); } } Czytanie przyrostowe (do wykorzystania przy czytaniu plików o dużych rozmiarach) : public void indexDocument(File file) throws Exception { Reader fulltext = tika.parse(file); try { Document document = new Document(); document.add(new Field("filename", file.getName(), Store.YES, Index.ANALYZED)); //Lucene supports reader instances as field values document.add(new Field("fulltext", fulltext)); writer.addDocument(document); } finally { fulltext.close(); } } 12. Parser Obiekt parsujący zawartość dokumentu import java.io.IOException; import java.io.InputStream; import java.util.Set; import org.apache.tika.exception.TikaException; import org.apache.tika.metadata.Metadata; import org.apache.tika.mime.MediaType; import org.apache.tika.parser.ParseContext; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; /** Tika parser interface. */ public interface Parser { /** Returns the set of media types supported by this parser. */ Set getSupportedTypes(ParseContext context); /** Parses a document stream into a XHTML SAX events and metadata. */ void parse( InputStream stream, ContentHandler handler, Metadata metadata, ParseContext context) throws IOException, SAXException, TikaException; }

Wybór parsera:  Przez programistę: Parser parser = new HtmlParser(); parser.parse(stream, handler, metadata, context);  Parser złożony: przykład wspiera pliki HTML oraz XML, a inne pliki parsuje jak zwykły tekst Map parsersByType = new HashMap(); parsersByType.put(MediaType.parse("text/html"), new HtmlParser()); parsersByType.put(MediaType.parse("application/xml"), new XMLParser()); CompositeParser parser = new CompositeParser(); parser.setParsers(parsersByType); parser.setFallback(new TXTParser());  Automatyczne wykrycie typu: Parser parser = new AutoDetectParser(); parser.parse(stream, handler, metadata, context);

13. Stream Strumień z plikiem wejściowym InputStream stream = new FileInputStream(new File(filename)); try { parser.parse(stream, handler, metadata, context); } finally { stream.close(); }

TikaInputStream 14. Handler (uchwyt) Właściwy format: ... ...

Hyperlink

In computing, a hyperlink (or link) is a reference to a document that the reader can directly follow, or that is followed automatically.

Content Handler widziałby następujące zdarzenia: 1. Start element h1 2. Output characters “Hyperlink” 3. End element h1 4. Start element p 5. Output characters “In ” 6. Start element a with a href attribute … 23. Output characters “document” 24. End element a 25. Output characters “ that the reader can ...” 26. End element p Dużo zdarzeń, więc Tika udostępnia klasy, która pozwalają na ich obsłużenie w uproszczony sposób:  BodyContentHandler – wydobywa zawartość tekstową z części fo zewnętrznego strumienia ByteArrayOutputStream  LinkContentHandler – wydobywa i standaryzuje linkii z  TeeContentHandler – dostarcza zdarzenia SAX do zbioru event handler, co umożliwiaj równoczesne przetwarzanie zawartości LinkContentHandler linkCollector = new LinkContentHandler(); OutputStream output = new FileOutputStream(new File(filename)); try { ContentHandler handler = new TeeContentHandler(new BodyContentHandler(output), linkCollector); parser.parse(stream, handler, metadata, context); } finally { output.close(); } 14. Metadane Obiekt przechowujący metadane o wybranym pliku public void indexWithDublinCore(File file) throws Exception { Metadata met = new Metadata(); met.add(Metadata.CREATOR, "Manning"); met.add(Metadata.CREATOR, "Tika in Action"); met.set(Metadata.DATE, new Date()); met.set(Metadata.FORMAT, tika.detect(file)); met.set(DublinCore.SOURCE, file.toURL().toString()); met.add(Metadata.SUBJECT, "File"); met.add(Metadata.SUBJECT, "Indexing"); met.add(Metadata.SUBJECT, "Metadata"); met.set(Property.externalClosedChoise(Metadata.RIGHTS, "public", "private"), "public"); InputStream is = new FileInputStream(file); tika.parse(is, met); try { Document document = new Document(); for (String key : met.names()) { String[] values = met.getValues(key); for (String val : values) { document.add(new Field(key, val, Store.YES, Index.ANALYZED)); } writer.addDocument(document); } } finally { is.close(); } }

15. Wykrywanie języka  domyślnie w Tika wykorzystuje się podejście oparte na 3-gramach

LanguageProfile profile = new LanguageProfile( "Alla människor är födda fria och lika i värde och rättigheter."); LanguageIdentifier identifier = new LanguageIdentifier(profile);

System.out.println(identifier.getLanguage( New LanguageProfile(FileUtils.readFileToString(new File(filename)))); 16. Zadanie do wykonania w grupach [8] Kolekcja dokumentów, której dotyczy zadania to zbiór plików PDF pobranych ze strony U.S. Federal Bureau of Investigation (http://vault.fbi.gov). Pliki zostały utworzone przez skanowanie oryginalnych dokumentów, więc jakość niektórych z nich pozostawia wiele do życzenia. W zależności od jakości OCR, Tika może nie wczytać poprawnie całego tekstu z pliku PDF. Chodzi jednak o to, by kolekcja tekstów miała charakter rzeczywistego zbioru danych. Pobierz ją z katalogu lab8 i rozpakuj.

Szkielet rozwiązania znajduje się w klasie TikaSkeleton.java, a zbiór słów, które będą wyszukiwane znajduje się w pliku queries.txt. Najłatwiejszym sposobem wykorzystania funkcjonalności Apache Tika jest pobranie: tika-app-1.4.jar. Zorganizuj folder z rozwiązaniem w następujący sposób:

+-- TikaSkeleton.java +-- tika-app-1.4.jar +-- queries.txt +-- tikadataset +--

Funkcjonalność programu ma być następująca:  akceptowanie pliku wejściowego, zawierającego dowolną liczbę zapytań w kolejnych liniach  iterowanie po kolekcji dokumentów,  wykorzystanie Apache Tika do wydobycia tekstu z plików pdf,  dla każdego pliku wypisanie języka (zidentyfikowanego przez Tika), autora, typu pliku oraz daty ostatniej modyfikacji,  przeszukanie tekstu ze względu na wystąpienie w nim zadanych zapytań,  zliczenie i wypisanie następujących statystyk:  liczba dokumentów zawierających zapytanie,  całkowita liczba wystąpień zapytania we wszystkich plikach,  lista plików zawierających zapytanie.

Klasa TikaSekeleton.java czyta plik queries.txt, zawierający zapytania oraz przegląda folder tikadataset, przetwarzając każdy plik pdf, który się w nim znajduje. Nie zmieniaj części programu oznaczonych przez "DO NOT MODIFY". Po wczytaniu tekstu z plików PDF, wyszukaj wyrażenia z pliku queries.txt. Sposób tego wyszukania zależy od Ciebie – możesz wykorzystać wbudowane funkcje do operacji na Stringach, wyrażenia regularne, a nawet Lucene. Odpowiednio inkrementuj liczniki num_fileswithkeywords oraz keyword_counts, gdy znajdziesz szukane wyrażenie w pliku. Zaimplementuj funkcje processFile oraz updatalogMetaData. Użyteczne klasy: Parser interface documentation: http://tika.apache.org/1.4/parser.html

PDFParser API: http://tika.apache.org/1.4/api/org/apache/tika/parser/pdf/PDFParser.html BodyContentHandler API: http://tika.apache.org/1.4/api/org/apache/tika/sax/BodyContentHandler.html Program powinien wypisywać następujące dane: w pliku output.txt:  listę szukanych wyrażeń,  liczbę przetworzonych plików,  liczbę plików zawierających wyrażenie,  liczbę wystąpień każdego wyrażenia w pliku log.txt:  nazwę pliku, jego autora, typ, datę ostatniej modyfikacji oraz wykryty język  informację o wykryciu wyrażenia wraz z jej czasem

Jako rozwiązanie prześlij TikaSkeleton.java, output.txt oraz log.txt.