Apache Tika to zestaw narzędzi do parsowania dokumentów od Apache Software Foundation: podaj mu plik niemal dowolnego typu, a zwróci zwykły tekst oraz ustandaryzowany słownik metadanych. README projektu deklaruje obsługę ponad tysiąca typów plików, a Tika osiąga to, dołączając wewnętrznie specjalistyczne biblioteki — PDFBox dla PDF-ów, Apache POI dla dokumentów Office, jsoup dla HTML, czytnik ODF dla ODT — dzięki czemu całość działa jako jeden duży plik JAR, bez konieczności pobierania czegokolwiek w czasie parsowania. W potoku danych to nieefektowny pierwszy etap: komponent stojący przed indeksem wyszukiwania, zbiorem do e-discovery albo korpusem dla LLM, który zamienia różnorodny stos plików w coś jednolitego. W praktyce chodzi o dwa zadania: rozpoznać, czym jest strumień bajtów, a potem wydobyć z niego tekst i metadane.
To jedno z najmniej wymagających narzędzi, jakie miałem ostatnio uruchomione. Jeden JAR, java -jar tika-app-3.3.2.jar --text file.pdf, bez pliku konfiguracyjnego, bez wag modelu, bez kroku po instalacji — i działał bezproblemowo na najnowszym JDK, które tego samego popołudnia zatrzymało na tym samym hoście inne narzędzia Java. Nie to jednak chciałem sprawdzić; ważniejsze pytanie jest węższe. Co Tika robi, gdy wejście kłamie? Zbudowałem więc kontrolowany zestaw testowy, w którym każdy blok treści ma unikalny znacznik, wyrenderowałem ten sam logiczny dokument do dziewięciu formatów nośnikowych, a potem zaatakowałem całość błędnymi rozszerzeniami, brakującymi rozszerzeniami, brakiem nazw plików, plikami zerobajtowymi i częściowo zapisanymi binariami.
Najciekawsze zachowanie pojawia się przy wykrywaniu typu. Przemianowałem PDF na .txt i spytałem Tikę, co to jest; odpowiedziała application/pdf. Potem całkiem usunąłem nazwę pliku, podałem surowe bajty przez stdin i dostałem ten sam wynik. We wszystkich pięciu formatach możliwych do rozpoznania po treści utrzymało się to w 20 unikalnych warunkach logicznych: trzy warunki związane z nazwą pliku plus jeden warunek bez nazwy pliku dla każdego formatu. Harness uruchomił przypadek ze strumieniem trzy razy pod różnymi etykietami, dając 30 poprawnych surowych uruchomień, ale te powtórzenia nie stanowią niezależnego dowodu. PDF i RTF ujawniają rozpoznawalne bajty; DOCX zdradza swój kontener; HTML i XML można zidentyfikować po znacznikach albo treści root. Inny mechanizm, ten sam użyteczny efekt w tym zestawie testowym: rozszerzenie nie przebiło treści. Jest też tryb dla rodziny tekstowej, w którym Markdown spada do text/plain natychmiast, gdy nazwa pliku jest błędna albo jej nie ma. Tutaj jego tożsamość opierała się wyłącznie na .md.
Dwa zastrzeżenia dotyczą wszystkiego, co dalej. Testowałem Apache Tika 3.3.2 — sprawdzone 27 lipca 2026, nadal była to najnowsza stabilna wersja; linia 4.0.0 istnieje tylko jako buildy alpha i beta na Maven Central. Projekt miał wtedy około 3,9 tys. gwiazdek na GitHubie i jest objęty licencją Apache-2.0, czyli tak przyjazną komercyjnie, jak się da. I nie testowałem OCR w ogóle. Ani jednej skanowanej strony, ani jednego PDF-a wyłącznie z obrazem. Na maszynie, na której to uruchomiłem, nie ma Tesseracta ani popplera, więc każda ścieżka OCR była zablokowana, zanim w ogóle ruszyła. Nie ma tu żadnych wyników OCR, bo po prostu nie ma żadnych wyników OCR.
Czym Tika jest naprawdę, gdy przestaniesz czytać marketing z pudełka
Powszechne założenie jest takie, że Apache Tika to konwerter dokumentów — wrzucasz DOCX, dostajesz czysty Markdown z zachowanymi nagłówkami i tabelami. To nie to, i im szybciej to zrozumiesz, tym lepiej narzędzie wypada.
Testowana tutaj ścieżka ma trzy istotne etapy: detektor typu treści, dispatcher, który przekazuje bajty do właściwego parsera, oraz obsługę wyjścia CLI --text, która emituje płaski tekst wraz z osobno dostępnymi metadanymi. W tym kontrakcie wyjścia nie ma obiektów Title, nie ma ListItem, nie ma też odtworzonej siatki tabeli. Tika udostępnia również inne handlery i API, w tym wyjście oparte na XHTML/SAX; tego nie testowałem. Każdy wniosek o strukturze poniżej dotyczy więc tika-app --text, a nie tezy, że zestaw narzędzi nigdzie nie ma żadnego uporządkowanego strumienia zdarzeń.
Brzmi to jak ograniczenie i w jednej osi nim jest. Ale oznacza też, że Tika nie ma czego błędnie sklasyfikować, a to dokładnie taki kompromis, jaki w drugą stronę składają bardziej „sprytne”, ale głośniejsze narzędzia.
Sam mechanizm wykrywania działa w udokumentowanej kolejności: najpierw sygnatura bajtowa, potem analiza korzenia XML, potem dopasowanie po nazwie pliku, a na końcu typ podany przez użytkownika (dokumentacja wykrywania Tiki opisuje to wprost). Dopiero po rozpoznaniu typu dispatcher przekazuje bajty do pasującego dołączonego parsera — PDFBox, POI, jsoup, TextAndCSVParser dla rodziny tekstowej.
To rozdzielenie wykrywania od parsowania nie jest technicznym drobiazgiem. Dzięki niemu plik zbyt uszkodzony, by go sparować, nadal może zostać poprawnie rozpoznany — i właśnie to staje się najpraktyczniejszą sztuczką, jaką Tika oferuje, kiedy zaczynają się problemy.
Konfiguracja: jeden JAR, jedno polecenie i JVM, która nie jest wybredna
Instalacja to po prostu pobranie pliku. tika-app-3.3.2.jar z Maven Central waży około 67 MB — to duży JAR zawierający wszystkie parsery — a potem wystarczy java -jar tika-app-3.3.2.jar --text file.pdf. Bez pliku konfiguracyjnego, bez wag modelu, bez kroku po instalacji, bez łańcucha brew install do przejścia.
Zaskoczyła mnie historia z JDK. Uruchomiłem całość na OpenJDK 26.0.1, niestabilnej, najnowszej wersji spoza LTS, i --version, --text, --metadata oraz --detect wszystkie zwracały kod wyjścia 0 bez żadnych uwag o zgodności. Warto o tym wspomnieć, bo tego samego dnia sprawdzałem Apache Nutch na tym samym hoście i jego cykl crawl w ogóle nie działał na JDK 26 — wymaga LTS 21 lub niżej z powodu usunięcia SecurityManagera w nowszych JDK. Tika to zignorowała. Jeśli unikasz narzędzi JVM przez dokładnie taki rodzaj problemów, Tika nie jest miejscem, w którym cię to ugryzie.
Dwie uczciwe uwagi po stronie konfiguracji. CLI uruchamia za każdym razem nową JVM, więc cold start jest realny — 131 wywołań w moim harnessie zajęło około minuty, głównie przez rozgrzewkę JVM. Jeśli przetwarzasz pliki masowo, chcesz biblioteki albo trybu serwerowego, a nie pętli shellowej wokół JAR-a. I historia „bez zależności” ma twardy kraniec: wydobycie tekstu z PDF bez OCR nie wymaga niczego zewnętrznego, ale OCR już tak — potrzebuje tesseracta i popplera. PDF-y z warstwą tekstową, DOCX, ODT, RTF, HTML, XML, TXT, Markdown i CSV parsowały się na hoście, na którym nie było nic z tego zainstalowane. Skanowane dokumenty nie przeszłyby, i nie próbowałem udawać, że jest inaczej.
Ten kontrast jest jeszcze wyraźniejszy przy bibliotekach siostrzanych, które testowałem tego samego dnia, unstructured, gdzie ścieżka dla elektronicznych PDF-ów była całkowicie zablokowana, bo import modułu PDF ładuje stos inferencji (torch i podobne) już przy imporcie — zanim dojdzie do wyboru strategii, więc nawet strategia „fast” nie zaimportuje się bez tego. Tika wyciągnęła tekst z tego samego PDF-a zwykłym java -jar.
Test kłamiących rozszerzeń: wykrywanie MIME, które ignoruje to, jak nazwałeś plik

Osiem formatów, każdy pokazany z poprawnym rozszerzeniem, specjalnie błędnym rozszerzeniem albo bez rozszerzenia, plus strumień bajtów bez nazwy pliku na stdin. To daje 32 unikalne warunki logiczne. Oryginalny harness uruchamiał też identyczne bajty strumienia raz pod każdą etykietą nazwy pliku, co dało 48 surowych wykonaniań; te trzy wiersze dotyczące strumienia zwijają się do jednego warunku, bo stdin nie niesie nazwy pliku.
| Zestaw testowy | Rzeczywisty typ | Przemianowany na | Poprawne rozszerzenie | Kłamiące rozszerzenie | Bez rozszerzenia | Surowy strumień, bez nazwy pliku |
|---|---|---|---|---|---|---|
application/pdf | .txt | ✅ | ✅ | ✅ | ✅ | |
| DOCX | OOXML wordprocessingml | .jpg | ✅ | ✅ | ✅ | ✅ |
| RTF | application/rtf | .html | ✅ | ✅ | ✅ | ✅ |
| HTML | text/html | .csv | ✅ | ✅ | ✅ | ✅ |
| XML | application/xml | .txt | ✅ | ✅ | ✅ | ✅ |
| Zwykły tekst | text/plain | .pdf | ✅ | ✅ | ✅ | ✅ |
| Markdown | text/markdown | .pdf | ✅ | ❌ text/plain | ❌ text/plain | ❌ text/plain |
| CSV | text/csv | .txt | ✅ | ❌ text/plain | ❌ text/plain | ❌ text/plain |
(Kolumna strumienia zwija wszystkie trzy warunki związane z rozszerzeniem, bo bez nazwy pliku nie ma czego dopasować po globie.)
Pięć formatów rozpoznawalnych po treści — PDF, DOCX, RTF, HTML i XML — trafiło w poprawny typ w 20 z 20 unikalnych warunków (oraz w 30 z 30 surowych uruchomień harnessu, licząc powtórzone uruchomienia strumienia). PDF nazwany report.txt nadal pozostawał PDF-em. DOCX nazwany photo.jpg nadal był DOCX-em. Nie potrzebowały nazwy pliku. Nie znaczy to jednak, że wszystkie pięć typów korzysta z niezmiennych sygnatur bajtowych: PDF i RTF mają rozpoznawalne nagłówki, DOCX jest kontenerem opartym na ZIP-ie, a HTML/XML rozpoznaje się po znacznikach albo treści root. W tych fixture’ach kłamliwe rozszerzenie nie wygrało.
Potem wchodzi reżim rodziny tekstowej. Markdown rozpoznawał się jako text/markdown tylko wtedy, gdy widoczne było rozszerzenie .md. Zmień je, usuń rozszerzenie albo wyślij plik jako strumień — i w tym teście spadał do text/plain. CSV zachowywał się podobnie na tym celowo małym gridzie: text/csv pojawiało się tylko z globu .csv. Licząc unikalne warunki, Markdown i CSV w każdym z czterech warunków rozpoznawały się jako swój własny typ tylko raz; zwykły tekst już był text/plain, więc nie miał z czego się „zawalić”. Surowy harness 48 uruchomień nadal jest przydatny jako zapis powtarzalności, ale nie jako większy mianownik.
Jeden szczegół działa na korzyść Tiki: kłamliwe rozszerzenie też nie wygrywa. Mój fixture Markdown przemianowany na .pdf wrócił jako text/plain, a nie application/pdf. Tika nie uwierzyła w kłamstwo; po prostu nie mogła potwierdzić prawdy. Degradacja do typu nadrzędnego to znacznie lepsza porażka niż pewne stwierdzenie błędnego typu, a fakt, że text/markdown jest udokumentowanym podtypem text/plain, czyni ten fallback zasadniczym, a nie przypadkowym.
Przy CSV jest jednak zastrzeżenie. Tika ma statystyczny detektor CSV i w czasie parsowania — potwierdza to łańcuch X-TIKA:Parsed-By, w którym pojawia się TextAndCSVParser — moja mała siatka 2 kolumn na 3 wiersze została rozpoznana jako text/plain, a nie text/csv. To pojedyncza obserwacja na celowo minimalnym fixture. Większy lub cytowany CSV może równie dobrze uruchomić detektor. Nie twierdzę, że wykrywanie CSV po treści jest zepsute; twierdzę, że na tym gridzie to rozszerzenie zadecydowało o text/csv.
Dlaczego ma to znaczenie w realnym pipeline uploadów
Konkretny scenariusz to router uploadów. Załóżmy, że przyjmujesz pliki użytkowników i kierujesz je według typu: PDF-y do parsera faktur, arkusze do importera księgi, wszystko inne do indeksu tekstowego. Jeśli ufasz rozszerzeniu, ktoś wrzucający PDF-a nazwanego notes.txt trafi do złej gałęzi — a to jeszcze łagodny przypadek; złośliwa wersja to plik poliglot z przyjaznym rozszerzeniem.
Dla binarnych i znacznikowych fixture’ów testowanych tutaj Tika kierowała się treścią nawet wtedy, gdy nazwa pliku zniknęła, co jest przydatne, gdy magazyn obiektowy albo handler ciała HTTP tę nazwę już utracił. Ten wynik nie obejmuje jednak długiego ogona Tiki, plików niejednoznacznych ani poliglotów. Testowane fixture’y z rodziny tekstowej zachowały się inaczej: gdy pipeline usuwał nazwy plików, Markdown i CSV trafiały jako text/plain, więc reguły oparte na ich konkretnych typach mediów przestawały działać. Zachowuj oryginalną nazwę jako metadane pomocnicze, zamiast liczyć, że detekcja treści ją odtworzy.
Wgrana treść przetrwała. --text spłaszczył strukturę.
Wierność to druga oś i rozdziela się tu bardzo wyraźnie. Jeden kanoniczny dokument (nagłówki, dwa akapity treści, lista punktowana, lista numerowana, końcowy akapit) wyrenderowałem do HTML, Markdowna, zwykłego tekstu, DOCX, PDF, RTF, ODT i XML, a dodatkowo dokument tabelaryczny do HTML, Markdowna, tekstu, DOCX, CSV i XML. Czternaście renderowań nośnikowych. Każdy blok ma unikalny znacznik — zztitle1, zzitem3, zztblcell_beta i tak dalej — więc „przetrwał” kontra „zniknął” to dokładny test podciągu, a nie ocena uznaniowa.
Odzysk znaczników był równy 1,000 we wszystkich czternastu renderowaniach. Nie zginął ani jeden wgrany znacznik: każda oznaczona komórka tabeli, pozycja listy i nagłówek były obecne. Trzy lokalne powtórzenia dla każdego nośnika po rozgrzaniu zwracały identyczne bajtowo wyjście --text. Ten test nic nie mówi o nieoznaczonych znakach, kolejności, białych znakach, normalizacji Unicode, treściach powtórzonych, linkach, nagłówkach, przypisach ani obiektach osadzonych. To sprawdzanie obecności bloków, nie dowód pełnej wierności dokumentu.
Płaskie wyjście tekstowe porzuca większość struktury źródła.
Oto dokument HTML z tabelą po wyjściu --text:
Tool Throughput
zztblcell_alpha 120
zztblcell_beta 95
Wiersze połączone tabulatorami. Wiersz nagłówka nie jest oznaczony jako nagłówek. Nie ma siatki, nie ma granic komórek poza tabulatorem, nie da się stwierdzić, że kiedykolwiek był tam <table>. Tabela z DOCX spłaszcza się dokładnie tak samo.
Listy są subtelniejsze i zależą od tego, co naprawdę było w źródle:
| Czym był punkt w źródle | Nośniki | Co zwraca --text |
|---|---|---|
Dosłowny znak — te renderowania zapisywały - jako zwykły tekst | zwykły tekst, Markdown, RTF, ODT, PDF | - zostaje, bo Tika po prostu przepuszcza znaki |
Prawdziwa struktura — HTML <li>, styl DOCX List Bullet | HTML, DOCX | znacznik znika całkowicie i zostaje sam tekst elementu: w HTML z wcięciem tabulatorem, w DOCX jako zwykła linia bez ozdobników |
Tika nigdy nie odtwarza znacznika, którego nie dostała jako tekstu. Ta sama treść, inne wizualnie wyjście.
Przypadek Markdown pokazuje to najczytelniej. Podaj Tikce plik .md z tabelą pipe, a znaki | wracają dosłownie, co wygląda jak zachowanie struktury. Ale nim nie jest. Tika potraktowała to jako tekst i oddała bajty z powrotem. Nic nie „zrozumiało” tej tabeli.
Mierzony kontrakt jest więc węższy: wszystkie wgrane znaczniki przetrwały, ale --text nie zachował typowanych elementów ani siatki tabeli możliwej do odtworzenia. Nazwanie tego błędem parsera mijałoby się z celem. Płaskie wydobycie tekstu celowo unika problemu klasyfikacji elementów; nie może też zaspokoić potrzeb downstreamu, który wymaga tych typów elementów. Jeśli potrzebujesz typowanych bloków albo odtworzonych tabel, --text jest tylko jednym komponentem stosu, nie całym stosem. Inne handlery Tiki mogą ujawniać więcej struktury, ale nie były objęte tym przebiegiem.
Standardowe zastrzeżenie do każdej liczby wierności tutaj: pochodzą z kontrolowanych, syntetycznych fixture’ów na jednej maszynie, jednej wersji i jednym JDK. Pokazują, że oznaczone bloki były obecne w wyjściu. Nie dowodzą zachowania znak w znak ani dokładności na chaotycznym, rzeczywistym korpusie.
Metadane: ustandaryzowane i odświeżająco niechętne do wymyślania czegokolwiek

W każdym nośniku, który ma warstwę metadanych, osadziłem znane wartości autora, tytułu i daty utworzenia, a potem sprawdziłem, co wróciło.
| Nośnik | author → dc:creator | title → dc:title | created → dcterms:created |
|---|---|---|---|
HTML (<meta name=author>, <title>) | ✅ | ✅ | nieosadzone |
| DOCX (właściwości core) | ✅ | ✅ | ✅ dokładnie 2021-03-15T09:30:00Z |
| PDF (słownik info) | ✅ | ✅ | obecne, ale to był własny znacznik czasu generatora — nieoceniane |
ODT (meta.xml) | ✅ | ✅ | ✅ dokładnie 2021-03-15T09:30:00Z |
| TXT / MD / CSV / RTF / XML | brak warstwy metadanych | — | — |
Autor i tytuł zostały odzyskane na 4 z 4 nośników z metadanymi, i — to właśnie jest ważne — są ustandaryzowane. HTML-owy <meta name="author">, właściwość core DOCX, wpis /Author w PDF i element dc:creator w ODT trafiają pod ten sam klucz dc:creator. Piszesz jednego konsumenta, nie czterech.
created to uczciwa chwiejność. DOCX i ODT zwróciły dokładnie osadzony przeze mnie timestamp z 2021 roku. PDF zwrócił datę utworzenia, ale była to data nadana przez bibliotekę generatora w momencie budowania, a nie wartość, którą chciałem osadzić — więc zaliczam ją jako obecne, nie odzyskane. Formaty bez warstwy metadanych nie pokazały nic, co jest poprawną odpowiedzią. Tika nie zgaduje autora na podstawie treści.
Celowe psucie wejścia i wynikająca z tego sztuczka triage
Cztery wrogie wejścia. Plik zerobajtowy. Poprawny nagłówek PDF z odciętym ciałem. Przycięty ZIP DOCX. I plik UTF-8 z wielobajtowymi znakami, bez BOM i bez deklaracji kodowania. To lokalne kształty fixture’ów, nie progi Tiki.
Podstawowy harness, wygenerowane fixture’y, surowy JSON, checksum JAR-a i manifest środowiska nie są tu publicznie podlinkowane, więc zewnętrzny czytelnik nie może niezależnie odtworzyć dokładnych mianowników. Traktuj więc tabele jako zaobserwowane wyniki, a nie dowód weryfikowalny przez stronę trzecią.
| Wejście | --text / --json | Co rzuciło | --detect |
|---|---|---|---|
| Plik 0-bajtowy | exit 1, pusty stdout | ZeroByteFileException: InputStream must have > 0 bytes | exit 0 → text/plain z nazwą pliku, application/octet-stream ze strumienia |
| Przycięty PDF | exit 1, pusty stdout | TikaException: TIKA-198: Illegal IOException from PDFParser | exit 0 → application/pdf |
| Przycięty DOCX | exit 1, pusty stdout | BŁĄD POI: "XML document structures must start and end within the same entity" | exit 0 → typ OOXML |
| UTF-8, bez BOM, bez deklaracji | exit 0 | nic | exit 0 → text/plain, charset UTF-8 |
Ekstrakcja kończy się głośnym błędem, a te awarie mają tę samą zewnętrzną postać. Plik zerobajtowy, przycięty PDF i przycięty DOCX każdy zwróciły wyjątek, exit 1 i pusty stdout. CLI nie „połyka” awarii w schludny pusty wynik. Z punktu widzenia bezpieczeństwa procesu jest w porządku — brak zwisu, brak segfaulta — ale wywołujący musi sprawdzać status wyjścia i stderr, a nie tylko pusty string.
Wykrywanie jest odseparowane od parsowania. Dla obu przyciętych binariów --detect zwróciło exit 0 z oczekiwanym typem na podstawie nienaruszonego początkowego fragmentu; dopiero parser wyłożył się na uszkodzonym ciele. Pipeline może więc użyć detekcji jako osobnego sygnału triage przed lub po nieudanym parsowaniu. Czy strategia detect-first to dobry domyślny wybór, zależy od trybu wdrożenia: tego testu nie benchmarkowałem pod kątem detect-first vs parse-only, a dwa świeże JVM CLI mogą być przy dużej skali złym kompromisem.
Wykrywanie kodowania działa. Plik UTF-8 bez BOM i bez deklaracji został zdekodowany jako UTF-8, a 日本語テスト przeszło bez zmian. Małe zastrzeżenie dla czytających słowniki metadanych: moje czysto ASCII-fixture’y raportują charset=ISO-8859-1, co na bajtach ASCII jest nieodróżnialne od UTF-8. To nie jest pudło, tylko remis.
Tika obok unstructured: te same typy plików, inne zadania
Oba narzędzia były użyte w tej samej sesji badawczej, ale to taksonomia kontraktów wyjścia, a nie symetryczny benchmark. Oceniano je pod kątem innych rezultatów.
Powiązana recenzja: Recenzja Unstructured.
| Apache Tika | unstructured | |
|---|---|---|
| Na czym to mierzyłem | wierność treści: czy coś zniknęło? | wierność klasyfikacji elementów: czy każdy blok dostał właściwy typ? |
| Wynik | wszystkie wgrane znaczniki obecne we wszystkich czternastu renderowaniach | w osobnym teście klasyfikacji zwykła tabela tekstowa osiągnęła recall Table równy 0,000, a jeden nagłówek zawierający czasownik został sklasyfikowany jako tekst narracyjny |
| Zwracane elementy typowane | brak — żadna struktura nie wróciła | Title, NarrativeText, ListItem, Table — dokładnie to, czego Tika nie robi |
| OCR | zablokowane na moim hoście, brak tesseracta | zablokowane na moim hoście, brak tesseracta |
Płaskie wyjście zachowujące znaczniki kontra typowane elementy z obserwowanymi błędami klasyfikacji. Wybór zależy od tego, czego potrzebuje downstream. Jeśli chodzi o indeks wyszukiwania albo okno kontekstu LLM, zwykły tekst może wystarczyć. Jeśli liczy się typ elementu, ścieżka --text Tiki nie dostarczy takiego kontraktu.
Żadne z nich nie ma wyników dla skanowanych dokumentów.
Plusy i minusy
Plusy
- Wykrywanie typu treści ignorowało kłamiące nazwy plików w 20/20 unikalnych warunkach dla pięciu formatów rozpoznawanych po treści; powtórzone uruchomienia strumienia też się zgadzały.
- Każdy wgrany znacznik przetrwał we wszystkich 14 renderowaniach nośników, w tym oznaczone komórki tabeli i pozycje list.
- Powtarzalne w trzech lokalnych powtórkach: każdy nośnik zwracał w tym środowisku identyczny bajtowo tekst.
- Metadane ustandaryzowane między formatami —
dc:creator/dc:title/dcterms:createdniezależnie od źródła, odzyskane na 4/4 nośnikach z metadanymi. - Rzeczywiście bez zależności dla testowanych przeze mnie formatów: warstwa tekstowa PDF, DOCX, ODT, RTF, HTML parsują się z jednego JAR-a bez zewnętrznych binarek.
- Działa bez problemu na OpenJDK 26 — bez ograniczenia do LTS.
- Wykrywanie pozostaje poprawne (exit 0) na przyciętych binariach, dając wiarygodny sygnał triage, gdy parsowanie zawiedzie.
- Apache-2.0, dojrzały, aktywnie utrzymywany.
Minusy
- Tożsamość Markdowna i CSV zależy całkowicie od rozszerzenia pliku; 10 z 18 komórek bez sygnatury spadło do
text/plain, gdy nazwy pliku brakowało albo była błędna. --textnie zwraca elementów typowanych; siatki tabel spłaszczyły się do linii połączonych tabulatorami, a strukturalne znaczniki list zniknęły.- Ekstrakcja rzuca nieobsłużonym błędem na pustych i uszkodzonych wejściach; oba przypadki wyglądają identycznie z samego wywołania ekstrakcji.
- JAR 67 MB plus zimny start JVM przy każdym wywołaniu w trybie CLI.
- OCR i skanowane PDF-y nie były tu w ogóle testowane — brakowało tesseracta i popplera, więc nie ma żadnej tezy na temat tej ścieżki.
- Każda liczba tutaj pochodzi z syntetycznej prawdy wzorcowej na jednej maszynie i jednej wersji. Dokładność na rzeczywistym korpusie, pliki szyfrowane, dokumenty osadzone/rekurencyjne i przepustowość na dużą skalę nie były mierzone.
Kto powinien tego używać, a kto nie
Tika ma sens tam, gdzie wejściem są pliki, które już masz, a wyjściem ma być tekst plus metadane do indeksowania maszynowego. Indeksowanie wyszukiwania, e-discovery, przetwarzanie archiwów, podawanie korpusu do LLM, budowa warstwy walidacji typu treści dla upload pipeline. Jest przydatna jako pierwszy etap triage i normalizacji przed czymś inteligentniejszym: wykryj testowane typy, wyciągnij płaski tekst i przekaż dalej z wyraźnymi kontrolami treści, których pipeline nie może sobie pozwolić stracić.
Pomiń ją — a raczej, nie zatrzymuj się na --text — jeśli potrzebujesz typowanych elementów, odtworzonych tabel albo układu dokumentu. Pomiń ją też, jeśli twoje dokumenty są skanami, przynajmniej dopóki nie zainstalujesz tesseracta i nie zrobisz własnych pomiarów, bo ja żadnych nie mam. Przy pracy na większej skali warto porównać bibliotekę albo tryb serwerowy z CLI na reprezentatywnych dokumentach. Start procesu był widoczny w tym teście na małych plikach, ale nie mierzyłem przepustowości ani kosztu zasobów.
Jedna rzecz, która często zaskakuje: jeśli warstwa storage usuwa nazwy plików, a ty obsługujesz Markdown lub CSV, nie licz na to, że Tika odróżni je od zwykłego tekstu. Zachowaj oryginalną nazwę.
Alternatywy i miejsce Thunderbit
Najpierw uczciwe ustawienie ram, bo uczciwe porównanie tutaj dotyczy wejść, a nie jakości. Tika to darmowy, samohostowany zestaw narzędzi Apache-2.0 do parsowania plików. Plików, które masz na dysku albo w bucketcie. Nie pobiera stron, nie uruchamia JavaScriptu, nie walczy z anty-botem i nie udaje, że to robi.
To właśnie granica, przy której do architektury może wejść zarządzana usługa do ekstrakcji z sieci, w tym nasz własny Thunderbit: pobiera żywe strony, podczas gdy Tika parsuje pliki, które już są w twoim posiadaniu. Ten artykuł nie benchmarkował tych usług względem Tiki i nie są one zamiennikami dla tego samego wejścia.
Czysty podział: Tika do dokumentów, które już masz, zarządzane API do ekstrakcji do stron internetowych, które trzeba dopiero pobrać. Wiele pipeline’ów używa obu — crawl i ekstrakcja po stronie web, Tika dla załączników PDF i DOCX, które wracają.
Jeśli porównujesz szerzej w świecie open source, opisałem pełne porównanie open-source’owych scraperów, przegląd najbardziej użytecznych projektów scrapingowych na GitHubie, praktyczną recenzję Crawl4AI obejmującą podejście oparte na przeglądarce i Markdownie oraz szersze zestawienie narzędzi do scrapowania. Dla ścieżki no-code jest też poradnik, jak scrapować stronę z użyciem AI.
Wypróbuj Thunderbit do ekstrakcji danych z sieci
Werdykt
Czy warto używać Apache Tiki? Tak, jeśli twoim zadaniem jest zamienianie heterogenicznych plików na płaski tekst i ustandaryzowane metadane, a potem samodzielnie walidujesz pola lub znaczniki, których pipeline nie może stracić.
Najmocniejszą częścią tego testu był detektor. Zwrócił oczekiwany typ w 20 z 20 unikalnych warunków dla pięciu formatów rozpoznawalnych po treści, w tym dla strumieni bez nazwy pliku. Każdy wgrany znacznik przetrwał we wszystkich czternastu renderowaniach, a wyjście powtarzało się bajt w bajt w trzech lokalnych powtórkach. Użyteczny dowód. Nadal syntetyczny dowód. Uruchomienie tego z jednego JAR-a na tym JDK, bez zewnętrznych binarek dla testowanych ścieżek innych niż OCR, sprawiło, że wdrożenie było przyjemnie nudne.
Trzeba jednak dobrze dobrać skalę. Każda tabela wraca jako linie połączone tabulatorami. Każdy strukturalny znacznik listy znika. Markdown i CSV tracą tożsamość w momencie, gdy znika nazwa pliku. Puste pliki i uszkodzone pliki rzucają ten sam kształt błędu, a do rozróżnienia trzeba osobnego wywołania detect. A jeśli chodzi o OCR, czyli pytanie, które dla wielu użytkowników Tiki jest najważniejsze, nie mam nic do zaoferowania: nie mogłem tego uruchomić i nie będę zgadywał.
W tych granicach Tika wykonuje nieefektowną pracę z nietypową niezawodnością. Czyta bajty, a nie etykietę na pudełku. Tylko nie pytaj jej, jakiego kształtu były te bajty.
Wypróbuj Thunderbit do ekstrakcji danych z sieci Get Started Free
FAQ
Czy Apache Tika poprawnie rozpoznaje typ pliku, jeśli rozszerzenie jest błędne?
Dla pięciu testowanych tutaj formatów rozpoznawalnych po treści — tak. PDF, DOCX, RTF, HTML i XML zostały rozpoznane jako właściwy typ mediów we wszystkich 20 unikalnych warunkach logicznych (30 surowych uruchomień z powtórzonymi strumieniami), także przy mylących rozszerzeniach, braku rozszerzenia i strumieniach bez nazwy pliku. PDF nazwany .txt nadal wykrywał się jako application/pdf. Markdown i mały fixture CSV zależały od informacji o nazwie pliku i spadały do text/plain, gdy jej brakowało albo była błędna.
Czy Tika zachowuje tabele i strukturę dokumentu?
Nie w testowanym tutaj trybie --text. Siatki tabel wracały jako linie połączone tabulatorami, bez semantyki komórek czy nagłówków, a strukturalne znaczniki list (HTML <li>, styl DOCX List Bullet) znikały. Każdy wgrany znacznik przetrwał we wszystkich 14 renderowaniach nośników, ale nie dowodzi to pełnej wierności treści, a --text nie zwraca typów elementów. Jeśli potrzebujesz typowanych elementów albo odtworzonych tabel, przetestuj inny handler wyjścia Tiki albo użyj równolegle innego narzędzia.
Czy Apache Tika potrafi zrobić OCR ze skanowanych PDF-ów? Tika obsługuje OCR przez Tesseract, ale ja tego nie testowałem i żaden z tych wyników nie jest tego tezą. Na moim hoście testowym nie było Tesseracta ani popplera, więc każda ścieżka OCR i skanowanych obrazów była zablokowana, zanim w ogóle ruszyła. W tym teście nie ma żadnych wyników OCR. Jeśli OCR jest twoim use case’em, zainstaluj tesseract i przetestuj go samodzielnie — tę część Tiki traktuj tutaj jako niezweryfikowaną.
Co Tika robi z pustymi albo uszkodzonymi plikami?
Kończy się błędem, a nie cichym sukcesem. Plik 0-bajtowy rzuca ZeroByteFileException; przycięty PDF rzuca TikaException z PDFParser; przycięty DOCX rzuca błąd XML z POI. Wszystkie trzy zwracają exit 1 i pusty stdout, więc z samego wywołania ekstrakcji pusty i uszkodzony plik są nierozróżnialne. Detekcja pozostaje jednak odporna — --detect zwróciło exit 0 z poprawnym typem dla obu przyciętych binariów, więc to dobry krok triage przed wydawaniem kosztu parsowania.
Czego nie obejmowały testy Tiki? Czterech rzeczy, wprost. OCR i obrazy skanowane (zablokowane, nietestowane). Dokładność na rzeczywistym korpusie — wszystkie wyniki pochodzą z kontrolowanych syntetycznych fixture’ów z wgranymi znacznikami, więc mierzą wierność względem znanych etykiet, a nie trafność na chaotycznych realnych dokumentach. Koszt zasobów, przepustowość i maksymalne użycie pamięci, których nie mierzyłem. I długi ogon twierdzenia o „tysiącach typów plików”: testowałem dziewięć reprezentatywnych, bezzależnościowych formatów, nie cały katalog. Wszystko tutaj dotyczy Tika 3.3.2 na OpenJDK 26.0.1, macOS arm64, jedna maszyna.


