2018年8月28日

ElasticsearchでWikipediaの全文検索にチャレンジ (3)

前置き


前回の記事の続きです。推定所要時間はデータ投入と確認で4時間です。
なんか前置きってテンプレートの様に最初に必ず書くのがお約束になってきている。

本番データ投入


では、ハードディスクの残容量を確認して、本番データの投入を行ってください。
ちなみに、手元の環境では14GB程消費しました。

$WorkDir = "C:\Wikipedia"
$OutputDir = Join-Path $WorkDir "output"

# ■Wikipedia XMLデータ
$Columns = "id", "timestamp", "title", "text"

$HeaderFile = Join-Path $WorkDir "xmlHeader.txt"
$FooterFile = Join-Path $WorkDir "xmlFooter.txt"

$HeaderText = Get-Content $HeaderFile -encoding UTF8
$FooterText = Get-Content $FooterFile -encoding UTF8

# ■Elasticsearch 登録先情報
$Hostname = "localhost"
$PortNumber = 9200
$IndexName = "wikipedia"
$TypeName = "page"
$BaseURL = "http://${Hostname}:${PortNumber}"

# ■投入前確認(何も入っていないこと)
$APIURL = "/${IndexName}/${TypeName}/_search"
$RequestURL = $BaseURL + $APIURL
$Result = Invoke-RestMethod -Uri $RequestURL
ConvertTo-JSON $Result -Depth 10

# その他確認
Get-Date
Get-PSDrive

# ■Bulk投入定義
$APIURL = "/${IndexName}/${TypeName}/_bulk"
$RequestURL = $BaseURL + $APIURL
$ReqestType = "POST"
$BulkCommand = @{ "index" = @{ "_index" = $IndexName ; "_type" = $TypeName } } | ConvertTo-Json -Compress

# ■投入対象一覧生成 ※ファイル名の都合でソートは無意味である。
$FileList = Get-ChildItem $OutputDir | Sort-Object -Property Name

ForEach ($File in $FileList) {

 # XML生成
 $PageText = Get-Content $File.Fullname
 [xml]$XMLData = $HeaderText + $PageText + $FooterText

 # ■Bulk実行用のJsonデータ生成
 $BulkData = New-Object System.Collections.ArrayList # 新規配列
 ForEach ($page in $XMLData.mediawiki.page) {
  $Row = New-Object PSObject | Select-Object $Columns
  $Row.id = $page.id
  $Row.timestamp = $page.revision.timestamp
  $Row.title = $page.title
  $Row.text = $page.revision.text."#text"
  $JsonData = $Row | ConvertTo-Json -Compress

  $BulkData.Add($BulkCommand) > $Null
  $BulkData.Add($JsonData) > $Null
 }

 # ■ Bulk実行
 $JsonData = $( $BulkData -join "`n" ) + "`n"
 $PostParam = [System.Text.Encoding]::UTF8.GetBytes($JsonData) # 日本語が文字化けするのでUTF8を強制
 $Result = Invoke-RestMethod -Uri $RequestURL -Body $PostParam -ContentType 'application/json' -Method $ReqestType
 
 Write-Output $( $File.name + " : " + $(Get-Date) )

}

# ■投入結果確認
$APIURL = "/${IndexName}/${TypeName}/_search"
$RequestURL = $BaseURL + $APIURL
$Result = Invoke-RestMethod -Uri $RequestURL
ConvertTo-JSON $Result -Depth 10

# その他確認
Get-Date
Get-PSDrive

1ファイル投入毎に完了時刻を報告するようにしているので、2300ファイル分が大体どの程度で終わりそうかの目安にしてください。
1ファイル5秒なら3時間強くらいですよね、的な。

どうでもいい補足


ソートに関しては、1番目の記事で連番を桁数合わせてないのでうまくいきません。順番通りに投入する必要性は皆無なので問題ありませんが。
行き当たりばったり故の不具合である。
言い訳をすると、最初の時点で全件がどの程度あるのか想像がつかなかったので、何桁おけばいいのか判断できなかったというのがあります。
実際には2300ファイルだったので、安全マージンで1桁増やして変更すればよさそうです。
最初の記事にはコメントアウトで追記しておりますので、変更したい人はどうぞ。

[string]$( $PageCounter / $Cycle )
 ↓
$( $PageCounter / $Cycle ).ToString("00000")

ついでに細かい補足をしておくと、ファイルのエンコード指定は、初回はBOMなしUTF8なので必須ですが、一旦Powershellから出力したUTF8はBOMつきUTF8で出力されているので、それ以降は自動判定可能であるため指定不要です。
あと出力時の改行コードは本文はLFで最後だけCRLFと不一致になるけれども、Get-Contentに-rawオプションをつけていないので、改行を問わず1行1配列のArrayオブジェクトとして生成され、かつXMLオブジェクトに変換されてしまうので、改行コードの不一致について気にする必要はないでしょう。
多分Sakura Editorで開くと保存するときに直すかいと聞かれるはずなので補足しました。

全文検索


では、検索をしてみましょう。先日の記事で示したように、Elasticsearchが標準外の処理をしているのでここでPowershellはお役御免です。
Kibinaを起動しましょう。そしてDev toolsにて以下のクエリーを実行します。これは、「全文検索」というキーワードに対するスコアを取得します。
GET /wikipedia/page/_search?pretty
{
  "query":{
    "match":{
      "text":"全文検索"
    }
  },
  "_source": ["id", "title"],
  "size": 100
}
なお、量が量なので、kibana.ymlにてelasticsearch.requestTimeoutの値を増やさないと変わったクエリーを投げるとタイムアウトしまくる可能性がありますので注意してください。
掲示した検索クエリーの書き方も先ほどのサイトのページがヒットしたので、こちらを参考にいたしました。
http://pppurple.hatenablog.com/entry/2017/01/29/144132

そして、Powershellの活躍がないままなのは悔しいので、生成された結果のJsonをテキストファイルに納めて、強引に活躍の場を与えましょう。
$JsonText = Get-Content C:\Wikipedia\resultjson.txt
$JsonData = $JsonText | ConvertFrom-Json
$JsonData.hits.hits | Format-Table | Out-File C:\Wikipedia\resulttext.txt -encoding UTF8

テーブルフォーマットに直したことで、スコア順に1行ずつ並んでいるので、順位がわかりやすくなりました。 Apache Solrが16番目にランクインしたにも関わらず、Elasticsearchは92番手でした。もう少し頑張りましょう。

なお、続けて「桃太郎」というキーワードで検索を掛けたところ、上位に女性の名前が出てきたので、榊原郁恵がピーターパンやってたような感じかと思って本文を開いてみたら実はセクシー女優さんで、桃太郎映像出版というところが映像作品をリリースしてたからヒットしてしまったというオチでした。
子供向けを狙って検索してみるとオトナ向けの結果が出てしまう可能性に注意いただきたいと思った次第です。また無駄知識が増えてしまった。
次回の記事はPowershellの代わりにPythonを利用することにしました。Pythonに興味があったのでこれを機に覚えてみようということで。
開発環境がOS標準ではなくなるので、間にPythonの環境構築の記事を挟みます。

0 件のコメント:

コメントを投稿

TIPS:VSCodeで日本語化がうまくいかないとき

前置き Visual Studio Codeで拡張機能「 Japanese Language Pack for Visual Studio Code 」を入れたら日本語になりますよね。 でも、「 Remote Development 」で色々な環境を日本語化してると、偶に...