Haystackチュートリアルをやってみる: Preprocessing Your Documents
HaystackのDocumentStoreは、辞書型のデータの配列であることを期待している。以下のようなフォーマットになる。
docs = [
{
'content': DOCUMENT_TEXT_HERE,
'meta': {'name': DOCUMENT_NAME, ...}
}, ...
]
ということで、いろいろなファイルタイプのドキュメントを上記のフォーマットにしていくために用意されている前処理ツールの話。
Colaboratoryで進める。今回はGPUは不要。
インストール。ファイルフォーマット関連や前処理に必要なオプションが有効化されているのがわかる。
%%bash
pip install --upgrade pip
pip install farm-haystack[colab,ocr,preprocessing,file-conversion,pdf]
テレメトリー有効化。
from haystack.telemetry import tutorial_running
tutorial_running(8)
ロギング設定。
import logging
logging.basicConfig(format="%(levelname)s - %(name)s - %(message)s", level=logging.WARNING)
logging.getLogger("haystack").setLevel(logging.INFO)
サンプルデータを取得。
from haystack.utils import fetch_archive_from_http
doc_dir = "data/tutorial8"
s3_url = "https://s3.eu-central-1.amazonaws.com/deepset.ai-farm-qa/datasets/documents/preprocessing_tutorial8.zip"
fetch_archive_from_http(url=s3_url, output_dir=doc_dir)
サンプルのデータは以下の3つ。
!find data -type f -ls
Word文書、構造化されていないテキストデータ、あとPDF。
1573070 16 -rw-r--r-- 1 root root 12433 Oct 3 10:31 data/tutorial8/heavy_metal.docx
1573057 28 -rw-r--r-- 1 root root 27802 Oct 3 10:31 data/tutorial8/classics.txt
1573056 760 -rw-r--r-- 1 root root 775166 Oct 3 10:31 data/tutorial8/bert.pdf
Converters
Convertersクラスを使うと、一般的なファイルタイプをHaystackのパイプラインで使えるドキュメントに変換してくれる。
以下の例では、TextConverter/PDFToTextConverter/DocxToTextConverterを使って変換している。
from haystack.nodes import TextConverter, PDFToTextConverter, DocxToTextConverter, PreProcessor
converter = TextConverter(remove_numeric_tables=True, valid_languages=["en"])
doc_txt = converter.convert(file_path="data/tutorial8/classics.txt", meta=None)[0]
converter = PDFToTextConverter(remove_numeric_tables=True, valid_languages=["en"])
doc_pdf = converter.convert(file_path="data/tutorial8/bert.pdf", meta=None)[0]
converter = DocxToTextConverter(remove_numeric_tables=False, valid_languages=["en"])
doc_docx = converter.convert(file_path="data/tutorial8/heavy_metal.docx", meta=None)[0]
valid_languages
は言語変換ではなく、正しい言語で変換されているかのチェックのためのものらしい。
あと、Apache Tikaを利用したConverterもあるらしい。
こういうやつか
あとまるっとよしなにやってくれるユーティリティもある
from haystack.utils import convert_files_to_docs
all_docs = convert_files_to_docs(dir_path=doc_dir)
PreProcessor / Cleaning / Splitting
PreProcessorクラスはテキストをクリーニングしたり分割したりするのに使う。
from haystack.nodes import PreProcessor
preprocessor = PreProcessor(
clean_empty_lines=True,
clean_whitespace=True,
clean_header_footer=False,
split_by="word",
split_length=100,
split_respect_sentence_boundary=True,
)
docs_default = preprocessor.process([doc_txt])
print(f"n_docs_input: 1\nn_docs_output: {len(docs_default)}")
上記の例だと51個のドキュメントに分割されている。
n_docs_output: 51
クリーニング関連のオプション
-
clean_empty_lines
: 3行以上の空行を2行の空行に変換 -
clean_whitespace
: 行頭・行末の空白を除去 -
clean_header_footer
: ページごとに繰り返されるヘッダー・フッター行を削除
分割のオプション
-
split_by
- : 分割単位。以下より選択
- "word": 単語単位。セパレータが"\n"と同じことだと思う。
- "sentence": 文単位。セパレータが"."と同じことだと思う。
- "paragraph": 段落単位。セパレータが"\n\n"と同じことだと思う。
- ※細かく追いかけていないので上記は推測。
- : 分割単位。以下より選択
-
split_length
- 分割する数。
-
split_by:"word"
だったらn語みたいな感じだと思う。
-
split_overlap
: 分割時に重複させる数。 -
split_respect_sentence_boundary
- 文の境界を跨ぐか?
- デフォルトだと文の途中で分割しない
-
False
に設定すると文の途中で分割する
全部まとめるとこんな感じ
from haystack.utils import fetch_archive_from_http
from haystack.utils import convert_files_to_docs
from haystack.nodes import PreProcessor
doc_dir = "data/tutorial8"
s3_url = "https://s3.eu-central-1.amazonaws.com/deepset.ai-farm-qa/datasets/documents/preprocessing_tutorial8.zip"
fetch_archive_from_http(url=s3_url, output_dir=doc_dir)
all_docs = convert_files_to_docs(dir_path=doc_dir)
preprocessor = PreProcessor(
clean_empty_lines=True,
clean_whitespace=True,
clean_header_footer=False,
split_by="word",
split_length=100,
split_respect_sentence_boundary=True,
)
docs = preprocessor.process(all_docs)
print(f"n_files_input: {len(all_docs)}\nn_docs_output: {len(docs)}")
n_docs_output: 174
日本語の場合はトークナイザーを考える必要がある。
一応こういうのがあるようなので、日本語のトークナイザーを使うことはもしかしたらできるのかな?
さっきのやつは違う。Pre-TrainedなNLTK PunktSentenceTokenizerを用意するってことか。
多分この辺ができないと日本語は厳しいかも