Apache Tika - это кроссплатформенный набор инструментов, написанный на Java
для предварительной обработки и анализа текстовой информации - выделения мета-данных, извлечения текста из разнообразных форматов файлов, автоматического определения языка текста и т.д. Умеет эта штука делать много всего интересного, но мы сконцентрируемся на процессе генерации N-gram-файлов для интересующих языков, не поддерживаемых Tika из коробки, чтобы с их помощью можно было автоматически определять языки для текстов.
Для начала было бы неплохо скачать и попробовать запустить само приложение tika-app-1.2.jar ~ 27 МБ. Как и любое другое Java
приложение Tika можно запустить универсальным способом java -jar tika-app-1.2.jar --help
, хотя в Linux можно ещё проще:
~$ java -version
~$ chmod +x tika-app-1.2.jar
~$ ./tika-app-1.2.jar --help
Если на машине стоит Java
, после выполнения следует ожидать перечисление списка поддерживаемых команд. Предположим мы хотим посмотреть список поддерживаемых форматов входных файлов:
~$ ./tika-app-1.2.jar --list-supported-types
В результате будет выведен форматированный список, в котором выводится приблизительно такое содержимое, только намного больше:
application/pdf
alias: application/x-pdf
supertype: application/octet-stream
parser: org.apache.tika.parser.DefaultParser
application/msword
alias: application/vnd.ms-word
supertype: application/x-tika-msoffice
parser: org.apache.tika.parser.DefaultParser
Давайте уберём все строчки, которые начинаются с пробела, а затем посчитаем сколько их осталось:
~$ ./tika-app-1.2.jar --list-supported-types | sed '/^ /d'
~$ ./tika-app-1.2.jar --list-supported-types | sed '/^ /d' | wc -l
Таким образом Tika версия 1.2 из коробки поддерживает 1372 различных формата.
В текущей версии Tika поддерживается ~27 языков среди которых например точно нет турецкого - поставим себе задачу это поправить. Для выделения N-gram нам понадобится связный текст - чем больше тем лучше, и уверенность в том что мы заранее знаем язык этого текста. Для экспериментов вот нашелся в Гугле довольно большой ipa.pdf файл на турецком языке. Предлагаю проверить с помощью Tika действительно ли формат соответствует указанному расширению:
~$ ./tika-app-1.2.jar -d ipa.pdf
Вывод: application/pdf
. Ради интереса попросим вывести более подробно метаинформацию из файла:
~$ ./tika-app-1.2.jar -m ipa.pdf
ERROR - Error: Could not parse predefined CMAP file for 'Adobe-Ide-UCS2'
Content-Length: 9055059
Content-Type: application/pdf
Creation-Date: 2008-01-26T23:40:04Z
created: Sun Jan 27 01:40:04 EET 2008
date: 2008-01-26T23:40:04Z
dcterms:created: 2008-01-26T23:40:04Z
meta:creation-date: 2008-01-26T23:40:04Z
producer: PDF Creator Plus 4.0 - http://www.peernet.com
resourceName: ipa.pdf
xmp:CreatorTool: PDF Creator Plus 4.0 - http://www.peernet.com
xmpTPg:NPages: 2351
Ошибка Adobe-Ide-UCS2
связана скорее всего не с Tika, а с pdfbox - но в любом случае мы увидели что хотели, поэтому далее предлагаю эту ошибку просто игнорировать. Теперь извлечем из нашего pdf полезный текст:
~$ ./tika-app-1.2.jar -t ipa.pdf > trout
~$ ./tika-app-1.2.jar -T ipa.pdf > trout
~$ file -bi trout
Вывод последней команды: text/plain; charset=utf-8
. В случае -T
текст будет немного плотнее за счёт удаления лишних пробелов, отступов и т.д. В результате размер файла с полезным текстом ~5,6 МБ в сравнении с 9 МБ оригинального pdf. Ну и наконец попробуем автоматически определить язык документа:
~$ ./tika-app-1.2.jar -l ipa.pdf
Вывод: et
. Тут удивляться нечему - для корректного определения турецкого языка в Tika должен быть список N-gram, характерный для этого языка. Сгенерировать небходимый файл можно на основе имеющегося текста, где в следующей команде tr - это идентификатор турецкого языка в формате ISO 639-2.
~$ ./tika-app-1.2.jar --create-profile=tr -eUTF-8 trout
В результате появится файл tr.ngp. Tika считывает список .ngp профайлов из специального файла tika.language.properties
. Этот файл скрывается в недрах tika-app-1.2.jar, но его можно подменить - создать копию tika.language.override.properties
и сообщить об этом через java classpath
. После чего в tika.language.override.properties
необходимо расширить ключ languages
турецким языком (через запятую) и добавить новый ключ name.tr
со значением Turkish. Пробуем:
~$ mkdir -p org/apache/tika/language
~$ cp tr.ngp org/apache/tika/language
#cp tika.language.override.properties org/apache/tika/language
#tika.language.override.properties languages << tr
#tika.language.override.properties name.tr=Turkish
~$ java -cp .:tika-app-1.2.jar org.apache.tika.cli.TikaCLI -l \
http://tr.wikipedia.org/wiki/Linus_Benedict_Torvalds
Вывод: tr
. Ура ! Мы с Вами только что обучили Tika новому языку ! Теперь ещё одна дача - преобразовать tr.ngp в javascript:
LNG=`basename $1 .ngp`
SUM=0
for COUNT in $(sed '/^#/d;s/^\S\+\s\+\([0-9]\+\)$/\1/' $LNG.ngp)
do
SUM=`expr $SUM + $COUNT`;
done
echo "(function() {" > $LNG.js
echo "var ngrams = {" >> $LNG.js
perl -CSD -p -e 's{([^\t\n\x20-\x7E])}{sprintf "\\u%04x", ord $1}eg' \
-f $LNG.ngp | sed '/^#/d;s/^\(\S\+\)\s\+\([0-9]\+\)$/"\1":\2,/' >> $LNG.js
sed -i '$s/,$//' $LNG.js
echo "};" >> $LNG.js
echo "LanguageIdentifier.addProfile('$LNG', ngrams, $SUM);" >> $LNG.js
echo "}());" >> $LNG.js
Сохраним как ngp2js
, затем chmod +x ngp2js
и запускаем: ./ngp2js tr.ngp
. В результате будет сгенерирован tr.js
размером ~13 КБ.
Если очень коротко резюмировать - для генерации качественных N-gram файлов нужно много хорошего связного текста заранее известного языка. Сам процесс создания .ngp профайлов очень прост и требует минимум усилий.