wikipedia-utilsを試す
以下で紹介されていて気になっていた。
wikipediaからRAGとかで使うようなきれいなテキストを抽出するのは結構大変。自分もいくつかライブラリ試してみたりしたけど、必要な情報がきれいに取れない、いらない情報がついてくる、とか、使えるデータにしようと思うと結構手間がかかる。
とりあえず試してみる。
データセットはHuggingFaceで公開されているけど、ざっと検索してみた限り、競馬に関するものは殆ど出てこない。ということで、自分でデータを作ってみようと思う。
$ git clone https://github.com/singletongue/wikipedia-utils && cd wikipedia-utils
$ pyenv virtualenv 3.10.13 wikipedia-utils
$ pyenv local wikipedia-utils
$ pip install -r requirements.txt
データの作成にはいくつかの方法が用意されているので、順番に見ていく。
CirrusSeachのダンプファイルからページIDを抽出
ElasticSearchを使ったMediaWikiの検索拡張のダンプを使う
最新のダンプをダウンロード。10GBぐらいある。。。
$ wget https://dumps.wikimedia.org/other/cirrussearch/current/jawiki-20231204-cirrussearch-content.json.gz
全ページのページIDとリビジョンIDを抽出。約135万件。
$ python get_all_page_ids_from_cirrussearch.py \
--cirrus_file ./jawiki-20231204-cirrussearch-content.json.gz \
--output_file page-ids-jawiki-20231204.json
こんな感じのNDJSONができる。
{
"title": "トウカイテイオー",
"pageid": 54987,
"revid": 97745114,
"num_inlinks": 528,
"is_disambiguation_page": false,
"is_sexual_page": false,
"is_violent_page": false
}
ページのHTMLを抽出する。
上記で抽出したページIDを元にWikipediaのREST APIを叩いて、HTMLを抽出する。READMEにも書いてあるが、
- 全部取得するには1〜2日ぐらいはかかる。
- wikipediaのAPIにはレートリミット(200APIリクエスト/秒)があり、かつ、User Agentに連絡先を指定しなければならない
注意しないといけない。今回は全件必要ないので、いくつかリストアップしたものだけ取得するようにする。
{"title": "アーモンドアイ", "pageid": 3774537, "revid": 98033547, "num_inlinks": 460, "is_disambiguation_page": false, "is_sexual_page": false, "is_violent_page": false}
{"title": "アパパネ", "pageid": 1955838, "revid": 98174463, "num_inlinks": 304, "is_disambiguation_page": false, "is_sexual_page": false, "is_violent_page": false}
{"title": "コントレイル (競走馬)", "pageid": 4034158, "revid": 98127844, "num_inlinks": 475, "is_disambiguation_page": false, "is_sexual_page": false, "is_violent_page": false}
{"title": "シンザン", "pageid": 53253, "revid": 97835578, "num_inlinks": 808, "is_disambiguation_page": false, "is_sexual_page": false, "is_violent_page": false}
{"title": "シンボリルドルフ", "pageid": 54975, "revid": 97733678, "num_inlinks": 663, "is_disambiguation_page": false, "is_sexual_page": false, "is_violent_page": false}
{"title": "ジェンティルドンナ", "pageid": 2496693, "revid": 97539739, "num_inlinks": 494, "is_disambiguation_page": false, "is_sexual_page": false, "is_violent_page": false}
{"title": "スーパーシンザン", "pageid": 530225, "revid": 97486996, "num_inlinks": 11, "is_disambiguation_page": false, "is_sexual_page": false, "is_violent_page": false}
{"title": "スティルインラブ", "pageid": 53099, "revid": 97476762, "num_inlinks": 216, "is_disambiguation_page": false, "is_sexual_page": false, "is_violent_page": false}
{"title": "セントライト", "pageid": 73480, "revid": 97490161, "num_inlinks": 327, "is_disambiguation_page": false, "is_sexual_page": false, "is_violent_page": false}
{"title": "デアリングタクト", "pageid": 4115257, "revid": 97745727, "num_inlinks": 226, "is_disambiguation_page": false, "is_sexual_page": false, "is_violent_page": false}
{"title": "ディープインパクト (競走馬)", "pageid": 228773, "revid": 98262326, "num_inlinks": 1216, "is_disambiguation_page": false, "is_sexual_page": false, "is_violent_page": false}
{"title": "ナリタブライアン", "pageid": 39103, "revid": 98211355, "num_inlinks": 692, "is_disambiguation_page": false, "is_sexual_page": false, "is_violent_page": false}
{"title": "ミスターシービー", "pageid": 78923, "revid": 98211370, "num_inlinks": 515, "is_disambiguation_page": false, "is_sexual_page": false, "is_violent_page": false}
{"title": "メジロラモーヌ", "pageid": 87170, "revid": 97842727, "num_inlinks": 326, "is_disambiguation_page": false, "is_sexual_page": false, "is_violent_page": false}
{"title": "リバティアイランド", "pageid": 4703590, "revid": 98232586, "num_inlinks": 87, "is_disambiguation_page": false, "is_sexual_page": false, "is_violent_page": false}
$ python get_page_htmls.py \
--page_ids_file ./triple_crown.json \
--output_file ./triple_crown.json.gz \
--language ja \
--user_agent XXXX@XXXXX \
--batch_size 50
出来たファイルを見てみる。
$ zcat triple_crown.json.gz | jq -s ".[0]"
htmlにHTMLが含まれている。
{
"title": "アーモンドアイ",
"pageid": 3774537,
"revid": 98033547,
"url": "https://ja.wikipedia.org/api/rest_v1/page/html/%E3%82%A2%E3%83%BC%E3%83%A2%E3%83%B3%E3%83%89%E3%82%A2%E3%82%A4/98033547",
"html": "<!DOCTYPE html>\n<html prefix=\"dc: http://purl.org/dc/terms/ mw: http://mediawiki.org/rdf/\" about=\"https://ja.wikipedia.org/wiki/Special:Redirec(snip)</section></body></html>"
}
HTMLからパラグラフを抜き出す。
$ python extract_paragraphs_from_page_htmls.py \
--page_htmls_file ./triple_crown.json.gz \
--output_file ./paragraphs-triple_crown.json.gz \
--min_paragraph_length 10 \
--max_paragraph_length 1000
なるほど、無視されるものもあると。
[I 231208 00:14:42 extract_paragraphs_from_page_htmls:80] tags_to_extract: ['p']
[I 231208 00:14:42 extract_paragraphs_from_page_htmls:81] tags_to_remove: ['table']
[I 231208 00:14:42 extract_paragraphs_from_page_htmls:82] inner_tags_to_remove: ['sup']
[I 231208 00:14:42 extract_paragraphs_from_page_htmls:83] sections_to_ignore: ['脚注', '出典', '参考文献', '関連項目', '外部リンク']
出来たものを見てみる。
$ zcat paragraphs-triple_crown.json.gz | jq -s '.' | jq -r '.[] | select(.title=="アーモンドアイ")'
{
"id": "3774537-98033547-0",
"pageid": 3774537,
"revid": 98033547,
"paragraph_index": 0,
"title": "アーモンドアイ",
"section": "__LEAD__",
"text": "アーモンドアイ(欧字名:Almond Eye、2015年3月10日 - )は、日本の競走馬・繁殖牝馬。",
"html_tag": "p"
}
{
"id": "3774537-98033547-1",
"pageid": 3774537,
"revid": 98033547,
"paragraph_index": 1,
"title": "アーモンドアイ",
"section": "__LEAD__",
"text": "2018年、2020年のJRA賞年度代表馬、2018年の最優秀3歳牝馬、2020年の最優秀4歳以上牝馬である。",
"html_tag": "p"
}
(snip)
セクションはこんな感じになっている。
$ zcat paragraphs-triple_crown.json.gz | jq -s '.' | jq -r '.[].section' | sort -u
__LEAD__
エピソード
デビューまで
デビュー前
ローテーションを巡る批判
逸話・出来事
引退後
厩舎
概要
各方面への影響
騎手
競走成績
競走馬としての特徴
競走馬引退後
競走馬時代
経歴
血統
骨折により安楽死
主な産駒
種牡馬時代
種牡馬成績
出自
身体面での特徴
成績
生涯
戦績
特徴
特徴・評価
繁殖牝馬として
繁殖牝馬時代
評価
弥生賞ディープインパクト記念
来歴
戦績とかのテーブルデータも入ってんのかな。。。?とりあえず進めてみる。
テキストコーパスを作成
パラグラフからテキストコーパスを作る。以下の2つの方法があるが、今回はここまで進めてきた流れにそって前者をやる。時間をかけてまるっとやる場合は後者なんだろうと思われる。
- make_corpus_from_paragraphs.py
- make_corpus_from_cirrussearch.py
MeCabの辞書を指定して名前等が分割されないようにオプションを設定している様子。
MeCabを入れていなかったのでインストールする。
$ sudo apt install mecab libmecab-dev mecab-ipadic-utf8
辞書は果たしてこれはメンテされてるんだろうか。ちょっとわからないけど、とりあえず書いてあるとおりにやってみると・・・
$ git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git && cd mecab-ipadic-neologd
$ sudo bin/install-mecab-ipadic-neologd -n
[test-mecab-ipadic-NEologd] : Get difference between default system dictionary and mecab-ipadic-NEologd
[test-mecab-ipadic-NEologd] : Something wrong. You shouldn't install mecab-ipadic-NEologd yet.
[test-mecab-ipadic-NEologd] : Finish..
[install-mecab-ipadic-NEologd] : Please check the list of differences in the upper part.
[install-mecab-ipadic-NEologd] : Do you want to install mecab-ipadic-NEologd? Type yes or no
んー、処理の中身を読んでみたけど、Yahoo!Japanから検索の多いワードを引っ張ってきてパースしようとしてるみたいなんだけど、Yahoo!側のフォーマットが変わってしまったのかなんなのか、パース後のファイルが空になってて、そこでコケてる気がする・・・
とりあえず問題なさそうなのでYesで進める
で、 自分の環境では/usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologdに入った模様。
[install-mecab-ipadic-NEologd] : Install completed.
[install-mecab-ipadic-NEologd] : When you use MeCab, you can set '/usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd' as a value of '-d' option of MeCab.
[install-mecab-ipadic-NEologd] : Usage of mecab-ipadic-NEologd is here.
Usage:
$ mecab -d /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd ...
辞書が正しく読み込めるか確認。辞書指定なしデフォルトの場合。
$ echo "8月3日に放送された「中居正広の金曜日のスマイルたちへ」(TBS系)で、1日たった5分でぽっこりおなかを解消するというダイエット方法を紹介。キンタロー。のダイエットにも密着。" | mecab
8 名詞,数,*,*,*,*,*
月 名詞,一般,*,*,*,*,月,ツキ,ツキ
3 名詞,数,*,*,*,*,*
日 名詞,接尾,助数詞,*,*,*,日,ニチ,ニチ
に 助詞,格助詞,一般,*,*,*,に,ニ,ニ
放送 名詞,サ変接続,*,*,*,*,放送,ホウソウ,ホーソー
さ 動詞,自立,*,*,サ変・スル,未然レル接続,する,サ,サ
れ 動詞,接尾,*,*,一段,連用形,れる,レ,レ
た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ
「 記号,括弧開,*,*,*,*,「,「,「
中居 名詞,固有名詞,人名,姓,*,*,中居,ナカイ,ナカイ
正広 名詞,固有名詞,人名,名,*,*,正広,マサヒロ,マサヒロ
の 助詞,連体化,*,*,*,*,の,ノ,ノ
金曜日 名詞,副詞可能,*,*,*,*,金曜日,キンヨウビ,キンヨービ
の 助詞,連体化,*,*,*,*,の,ノ,ノ
スマイル 名詞,一般,*,*,*,*,スマイル,スマイル,スマイル
たち 名詞,接尾,一般,*,*,*,たち,タチ,タチ
へ 助詞,格助詞,一般,*,*,*,へ,ヘ,エ
」( 名詞,サ変接続,*,*,*,*,*
TBS 名詞,一般,*,*,*,*,*
系 名詞,接尾,一般,*,*,*,系,ケイ,ケイ
) 名詞,サ変接続,*,*,*,*,*
で 助詞,格助詞,一般,*,*,*,で,デ,デ
、 記号,読点,*,*,*,*,、,、,、
1 名詞,数,*,*,*,*,*
日 名詞,接尾,助数詞,*,*,*,日,ニチ,ニチ
たっ 動詞,自立,*,*,五段・タ行,連用タ接続,たつ,タッ,タッ
た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ
5 名詞,数,*,*,*,*,*
分 名詞,接尾,助数詞,*,*,*,分,フン,フン
で 助動詞,*,*,*,特殊・ダ,連用形,だ,デ,デ
ぽ 形容詞,接尾,*,*,形容詞・アウオ段,ガル接続,ぽい,ポ,ポ
っ 動詞,非自立,*,*,五段・カ行促音便,連用タ接続,く,ッ,ッ
こり 動詞,自立,*,*,一段,連用形,こりる,コリ,コリ
おなか 名詞,一般,*,*,*,*,おなか,オナカ,オナカ
を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
解消 名詞,サ変接続,*,*,*,*,解消,カイショウ,カイショー
する 動詞,自立,*,*,サ変・スル,基本形,する,スル,スル
という 助詞,格助詞,連語,*,*,*,という,トイウ,トユウ
ダイエット 名詞,サ変接続,*,*,*,*,ダイエット,ダイエット,ダイエット
方法 名詞,一般,*,*,*,*,方法,ホウホウ,ホーホー
を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
紹介 名詞,サ変接続,*,*,*,*,紹介,ショウカイ,ショーカイ
。 記号,句点,*,*,*,*,。,。,。
キンタロー 名詞,一般,*,*,*,*,*
。 記号,句点,*,*,*,*,。,。,。
の 助詞,連体化,*,*,*,*,の,ノ,ノ
ダイエット 名詞,サ変接続,*,*,*,*,ダイエット,ダイエット,ダイエット
に 助詞,格助詞,一般,*,*,*,に,ニ,ニ
も 助詞,係助詞,*,*,*,*,も,モ,モ
密着 名詞,サ変接続,*,*,*,*,密着,ミッチャク,ミッチャク
。 記号,句点,*,*,*,*,。,。,。
EOS
mecab-ipadic-neologdを指定した場合。
$ echo "8月3日に放送された「中居正広の金曜日のスマイルたちへ」(TBS系)で、1日たった5分でぽっこりおなかを解消するというダイエット方法を紹介。キンタロー。のダイエットにも密着。" | mecab -d /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd
8月3日 名詞,固有名詞,一般,*,*,*,8月3日,ハチガツミッカ,ハチガツミッカ
に 助詞,格助詞,一般,*,*,*,に,ニ,ニ
放送 名詞,サ変接続,*,*,*,*,放送,ホウソウ,ホーソー
さ 動詞,自立,*,*,サ変・スル,未然レル接続,する,サ,サ
れ 動詞,接尾,*,*,一段,連用形,れる,レ,レ
た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ
「 記号,括弧開,*,*,*,*,「,「,「
中居正広の金曜日のスマイルたちへ 名詞,固有名詞,一般,*,*,*,中居正広の金曜日のスマイルたちへ,ナカイマサヒロノキンヨウビノスマイルタチヘ,ナカイマサヒロノキンヨービノスマイルタチヘ
」( 記号,一般,*,*,*,*,*
TBS 名詞,固有名詞,一般,*,*,*,TBS,ティービーエス,ティービーエス
系 名詞,接尾,一般,*,*,*,系,ケイ,ケイ
) 記号,一般,*,*,*,*,*
で 助動詞,*,*,*,特殊・ダ,連用形,だ,デ,デ
、 記号,読点,*,*,*,*,、,、,、
1日 名詞,固有名詞,一般,*,*,*,1日,ツイタチ,ツイタチ
たった 副詞,助詞類接続,*,*,*,*,たった,タッタ,タッタ
5分 名詞,固有名詞,一般,*,*,*,5分,ゴフン,ゴフン
で 助詞,格助詞,一般,*,*,*,で,デ,デ
ぽっこりおなか 名詞,固有名詞,一般,*,*,*,ぽっこりおなか,ポッコリオナカ,ポッコリオナカ
を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
解消 名詞,サ変接続,*,*,*,*,解消,カイショウ,カイショー
する 動詞,自立,*,*,サ変・スル,基本形,する,スル,スル
という 助詞,格助詞,連語,*,*,*,という,トイウ,トユウ
ダイエット方法 名詞,固有名詞,一般,*,*,*,ダイエット方法,ダイエットホウホウ,ダイエットホウホー
を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
紹介 名詞,サ変接続,*,*,*,*,紹介,ショウカイ,ショーカイ
。 記号,句点,*,*,*,*,。,。,。
キンタロー。 名詞,固有名詞,一般,*,*,*,キンタロー。,キンタロー,キンタロー
の 助詞,連体化,*,*,*,*,の,ノ,ノ
ダイエット 名詞,サ変接続,*,*,*,*,ダイエット,ダイエット,ダイエット
に 助詞,格助詞,一般,*,*,*,に,ニ,ニ
も 助詞,係助詞,*,*,*,*,も,モ,モ
密着 名詞,サ変接続,*,*,*,*,密着,ミッチャク,ミッチャク
。 記号,句点,*,*,*,*,。,。,。
EOS
やっとコーパス作成。
$ export MECABRC=/etc/mecabrc # これを指定しないとmecabrcを見つけれずにコケた
$ python make_corpus_from_paragraphs.py \
--paragraphs_file ./paragraphs-triple_crown.json.gz \
--output_file ./corpus-triple_crown.txt.gz \
--mecab_option '-d /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd' \
--min_sentence_length 10 \
--max_sentence_length 1000
出来たファイルを見てみる
$ zcat corpus-triple_crown.txt.gz | perl -00 -wnl -e '/^アーモンドアイ/ and print'
アーモンドアイ(欧字名:Almond Eye、2015年3月10日 - )は、日本の競走馬・繁殖牝馬。
2018年、2020年のJRA賞年度代表馬、2018年の最優秀3歳牝馬、2020年の最優秀4歳以上牝馬である。
2023年、史上35頭目となるJRA顕彰馬に選出。
2006年のエリザベス女王杯(GI)を優勝した牝馬のフサイチパンドラと、2012年から2013年にかけてGI級競走を6勝した牡馬のロードカナロアの間に誕生した鹿毛の牝馬である。
2017年8月、新潟競馬場の新馬戦でニシノウララに敗れて2着となるも、10月の未勝利戦から、2019年3月のドバイターフまで7連勝。
この間に、史上5頭目の牝馬三冠を達成、ジャパンカップを世界レコードと広く認識されている記録よりも速いタイムで走破し優勝した。
4歳時の2019年は、ドバイターフ、天皇賞(秋)優勝。
5歳時の2020年は、ヴィクトリアマイル、天皇賞(秋)、ジャパンカップを優勝した。
2018年から2020年にかけて、史上5頭目となる牝馬三冠制覇、史上2頭目となる天皇賞(秋)連覇、史上2頭目となるジャパンカップ2勝を達成。
(snip)
なるほど、これは単純なテキストになる模様。
パッセージファイルを作る
パッセージは、セクション・パラグラフ・文章からなる塊のことらしい。
$ python make_passages_from_paragraphs.py \
--paragraphs_file ./paragraphs-triple_crown.json.gz \
--output_file ./passages-c400-triple_crown.json.gz \
--passage_unit sentence \
--passage_boundary section \
--max_passage_length 400 \
--as_long_as_possible
$ zcat passages-c400-triple_crown.json.gz | jq -s '.' | jq -r '.[] | select(.title=="アーモンドアイ")'
{
"id": 1,
"pageid": 3774537,
"revid": 98033547,
"title": "アーモンドアイ",
"section": "__LEAD__",
"text": "アーモンドアイ(欧字名:Almond Eye、2015年3月10日 - )は、日本の競走馬・繁殖牝馬。2018年、2020年のJRA賞年度代表馬、2018年の最優秀3歳牝馬、2020年の最優秀4歳以上牝馬である。2023年、史上35頭目となるJRA顕彰馬に選出。"
}
{
"id": 2,
"pageid": 3774537,
"revid": 98033547,
"title": "アーモンドアイ",
"section": "概要",
"text": "2006年のエリザベス女王杯(GI)を優勝した牝馬のフサイチパンドラと、2012年から2013年にかけてGI級競走を6勝した牡馬のロードカナロアの間に誕生した鹿毛の牝馬である。2017年8月、新潟競馬場の新馬戦でニシノウララに敗れて2着となるも、10月の未勝利戦から、2019年3月のドバイターフまで7連勝。この間に、史上5頭目の牝馬三冠を達成、ジャパンカップを世界レコードと広く認識されている記録よりも速いタイムで走破し優勝した。4歳時の2019年は、ドバイターフ、天皇賞(秋)優勝。5歳時の2020年は、ヴィクトリアマイル、天皇賞(秋)、ジャパンカップを優勝した。2018年から2020年にかけて、史上5頭目となる牝馬三冠制覇、史上2頭目となる天皇賞(秋)連覇、史上2頭目となるジャパンカップ2勝を達成。ドバイターフとヴィクトリアマイルを加え、日本調教馬として初めて芝GI級競走9勝を挙げた。"
}
{
"id": 3,
"pageid": 3774537,
"revid": 98033547,
"title": "アーモンドアイ",
"section": "概要",
"text": "2019/20シーズン、2020/21シーズンの香港競馬年度表彰で最優秀外国調教馬を受賞、ドバイでも2019年、2020年の最優秀競走馬を受賞した。また日本調教馬として初めて総獲得賞金が19億円に達し、日本馬の最多獲得賞金でもある。2020年TRC世界ランキング1位。JRA賞の他に、2018年から2020年にかけて3年連続東京競馬記者クラブ賞。また2020年朝日スポーツ賞の受賞は、競馬関係者としては騎手の武豊に続いて2例目、競走馬としては初であった。生まれ故郷の北海道安平町特別栄誉賞である。"
}
(snip)
あー、これはRAGで使うのにとても良さそう。
ElasticSearchのインデックスにもできる様子。OpenSearch-2.11あたりでやれば面白いのでは。
パッセージでまとめるのはいい感じに使えそう。ただ、今回の例だと、各競走馬の戦績とか血統みたいなテーブルデータの部分は取れてないので、この辺を少しいじって取ってくるようにするともっと使えそうな気はする。