はてだBlog(仮称)

私的なブログど真ん中のつもりでしたが、気づけばWebサイト系のアプリケーション開発周りで感じたこと寄りの自分メモなどをつれづれ述べています。2020年6月現在、Elasticsearch、pandas、CMSなどに関する話題が多めです。...ですが、だんだんとより私的なプログラムのスニペット置き場になりつつあります。ブログで述べている内容は所属組織で販売している製品などに関するものではなく、また所属する組織の見解を代表するものではありません。

続:ナレッジインデックスの有効性のゆるい確認、 続:検索練習用のサンプルデータのインポート(ElasticsearchのSignificant text )

はじめに

この記事は、

itdepends.hateblo.jp

のおおよその続編。

また、

itdepends.hateblo.jp

itdepends.hateblo.jp

の親戚記事です。

一言で言うと、「ナレッジインデックス(仮称)」というものを考えて、こいつの有効性を(実証は難しいものの)いくつか試してみるというものになります。

使用したElasticsearchのバージョンは6.4です。

アンサイクロペディアwikipediaから「東京関係」の解説記事を抜き出した上、Elasticsearchにまるっと放り込んで(これが別記事でナレッジインデックスと呼んでいるもの)、東京の地理に関する検索語(例: 上野)に関連するワードがが得られるかやって見るというものです。 (ここだけ見ると、Significant t... の当たり前の機能じゃん...ですが。)

wikipediaのデータをElasticsearchにインポートする正攻法は他のブログで有用な記事を皆さんが作成されています。この記事はそれらと少し趣がことなりますので、Google検索等で流れついた方は、ご容赦ください。また、自分の主張を卑下するわけではありませんが、この記事で言うナレッジインデックス(仮称)は少々名前負けしています。

アンサイクロペディアから東京エリアナレッジインデックス(仮称)生成

1) mapping設定します。

PUT your_index5
{
  "mappings": {
    "_doc": {
      "dynamic_templates": [
        {
          "dtmpl": {
            "match_mapping_type": "*",
            "match": "*_ja",
            "mapping": {
              "analyzer": "my_kuromoji",
              "fielddata":true
            }
          }
        }
      ]
    }
  },
  "settings": {
    "analysis": {
      "analyzer": {
        "my_kuromoji": {
          "type": "custom",
          "tokenizer": "kuromoji_tokenizer",
          "mode": "search",
          "char_filter": [
            "icu_normalizer",
            "kuromoji_iteration_mark"
          ],
          "filter": [
            "kuromoji_baseform",
            "kuromoji_part_of_speech",
            "ja_stop",
            "lowercase",
            "kuromoji_number",
            "kuromoji_stemmer"
          ]
        }
      }
    }
  }
}


2) アンサイクロペディアのデータをダウンロードします。

http://download.uncyclomedia.org/

http://download.uncyclomedia.org/ja-wiki.xml.gz

展開すると、12Gぐらいありました。

3) indexに入れるための、東京に関するデータを抽出します。

データを抜き出すためのツールを作成しました。

この、

# encoding: utf-8

# wiki_simple_ext.rb : 

#   アンサイクロペディアのデータの地域の説明はおおよそ次のようなXMLのスキーマになっているようだ。
#   なので目的の情報を持ってそうな、*印部分の要素を1行ずつ処理する。
#
# * page
# * title
# *   revision
# *      {東京} もしくは {XXX}
#     revision
#        {東京} もしくは {XXX}
#     ...

entry = ""
tokyo = false
revision = 0
STDIN.each_line do |l|
  if l.match(/<page>/)  then
    puts entry + "</page>" if tokyo == true
    entry = ""
    tokyo = false
    revision = 0
  end

  revision = revision + 1 if l.match(/<revision>/)
  entry = entry + l if revision <= 1
  tokyo = true if l.match(/\{\{(東京|東京都区部|東京都の鉄道駅|東京都の自治体|大阪)\}\}/)
end

puts entry + "</page>" if tokyo == true

を wiki_simple_ext.rbとして、

cat ja-wiki.xml | ruby wiki_simple_ext.rb  > ja-wiki-tokyo.xml

で、ja-wiki-tokyo.xmlを出力して*1

 export META='{"index":{}}'; cat ja-wiki-tokyo.xml | tr '"' ' ' | tr '\n' ' ' | tr '{' ' ' | tr '}' ' ' | sed 's/<\/page>/<\/page>"\'$'\n/g' |  sed 's/<title>/"title_ja":"/' | sed 's/<\/title>/","content_kw":"/g' | sed 's/<[^>]*>//g' | sed '/^ *$/d' |  ruby -nle 'puts ENV["META"] + "\n{" + $_ + "}"'   > ja_wiki_tokyo.json

で、バルクロードに向いた次の形式のJSONファイルにしてやります。

{"index":{}}
{       "title_ja":"葛飾区", "content_ja":"XXXXXXXXXX" }

4) バルクロード

ja_wiki_tokyo.json を次のコマンドでバルクロードします。 (今気づきましたが、アドホック手順とはいえ、ファイル名に規則性がなくて分かりづらいですね。)

 curl -H "Content-type: application/x-ndjson" -X POST localhost:9200/your_index5/_doc/_bulk?refresh --data-binary  @ja_wiki_tokyo.json

取り漏れが何件かあったようですが、ひとまずインポートできました。

5) significant_text*2で検索してみます。


POST /your_index5/_search
{
  "size": 0, 
  "query": {
    "match": {
      "content_ja": {
        "query": "上野",
        "operator": "and"
      }
    }
  },
  "aggs": {
    "titlegroup": {
      "terms": {
        "field": "title_ja"
      },
      "aggs": {
        "tokuchougo": {
          "significant_text": {
            "field": "content_ja"
          }
        }
      }
    }
  }
}

返ってきました↓。

          "key": "上野",   
          "bg_count": 14    
          "key": "東北",  
          "bg_count": 7 
          "key": "ターミナル", 
          "bg_count": 5 
          "key": "東北新幹線", 
          "bg_count": 4 
          "key": "東北本線",    
          "bg_count": 4 
          "key": "新幹線",   
          "bg_count": 4 
          "key": "常磐線",   
          "bg_count": 5 
          "key": "常磐",  
          "bg_count": 5 
          "key": "止める",   
          "bg_count": 3 
          "key": "起点",  
          "bg_count": 3 
          "key": "京成電鉄",    
          "bg_count": 3 
          "key": "何者",  
          "bg_count": 3 
          "key": "運転",  
          "bg_count": 3 
          "key": "京浜東北",    
          "bg_count": 3 
          "key": "本線",  
          "bg_count": 8 
          "key": "列車",  
          "bg_count": 6 
          "key": "京浜",  
          "bg_count": 4 
          "key": "御徒",  
          "bg_count": 4 
          "key": "始発駅",   
          "bg_count": 4 
          "key": "更に",  
          "bg_count": 4 

気持ちは分からんでもないが.... というところです。

ちなみに、アンサイクロペディアをチョイスしたのは、「危険」や「眠らない街」でSignificant_textで検索して「新宿」がヒットしたりしないかな〜、だと面白いな〜と考えたからですが、そこまで都合はよくありませんでした。

一応aggsをネストしたものもやってみましたが、結果は略します。(このaggsのネストに深い意図はないです。)

POST /your_index5/_search
{
  "size": 0, 
  "query": {
    "match": {
      "content_ja": {
        "query": "上野",
        "operator": "and"
      }
    }
  },
  "aggs": {
    "titlegroup": {
      "terms": {
        "field": "title_ja"
      },
      "aggs": {
        "tokuchougo": {
          "significant_text": {
            "field": "content_ja"
          }
        }
      }
    }
  }
}

wikipediaから東京エリアナレッジインデックス(仮称)生成

なんとなくとっつきやすかったのでアンサイクロペディアの方を先にやりましたが、最初から、より体系的に記述されているであろうwikipediaでよかったような気がしてきました...

多分同じようなフォーマットと思われるので(実際、今回やりたいことの範囲ではおおよそ同じスキーマ形式でした)同じ手順でやります。

1) wikipediaデータのダウンロード

https://dumps.wikimedia.org/jawiki/

https://dumps.wikimedia.org/jawiki/20181201/jawiki-20181201-pages-meta-current.xml.bz2

展開すると16GBぐらいでした。

2) wikipediaのデータの東京関連データ抽出

冒頭の絞り込みrubyツールをwikipedia用に見直しました。こいつにwikipediaxmlを食らわせて、 jawiki-mini.xmlというファイルを作ります。

# encoding: utf-8

# * page
# * title
# *   revision
# *      [Category:東京都の特別区...
#     revision
#        [Category:東京都の特別区...
#     ...

entry = ""
tokyo = false
revision = 0
STDIN.each_line do |l|
  if l.match(/<page>/)  then
    puts entry + "</page>" if tokyo == true
    entry = ""
    tokyo = false
    revision = 0
  end

  revision = revision + 1 if l.match(/<revision>/)
  entry = entry + l if revision <= 1
  tokyo = true if l.match(/\[Category:(東京都の特別区|東京都の市町村|東京都交通局の鉄道駅|..区の鉄道駅|...区の鉄道駅)\]/)
end

puts entry + "</page>" if tokyo == true

中途半端に同じようなコードを量産してしまいました。これなら有志の方が作成されているwikipediaXMLをパースするツール等を利用させてもらえばよかったようにも思いました。が、ひとまず続けます。

バルクロード用のJSONファイルを作ります。

export META='{"_____":{}}'; cat jawiki-mini.xml | tr '"' ' ' | tr '\n' ' ' | tr '{' ' ' | tr '}' ' ' | sed 's/<\/page>/<\/page>"\'$'\n/g' |  sed 's/<title>/"@@@":"/' | sed 's/<\/title>/","%%%":"/g' | sed 's/<[^>]*>//g' | sed '/^ *$/d' |  ruby -nle 'puts ENV["META"] + "\n{" + $_ + "}"' | sed 's/Category:/...:/g' | tr -d '[0-9A-Za-z]' | sed 's/@@@/title_ja/g' | sed 's/%%%/content_ja/g' | sed 's/_____/index/g'

ここまで書いて、ひょっとして簡易なXMLぐらいなら、サクッと読み込んでくれるkibanaとかlogstashとかの仕組みがあるのではと思いましたが、実のところよく知らないので、この方法に徹しました。

つづきます。

4) バルクロードします

JSONファイルをバルクロードします。

curl -H "Content-type: application/x-ndjson" -X POST localhost:9200/your_index_spot/your_type_spot/_bulk?refresh --data-binary  @jawiki-mini.json 

5) significant_textで検索してみます。

アンサイクロペディアの例と同じで、「上野」での検索です。

返ってきたのはコレ↓

          "key": "上野",
          "bg_count": 130
          "key": "京成",
          "bg_count": 102
          "key": "台東",
          "bg_count": 47
          "key": "御徒",
          "bg_count": 32
          "key": "御徒町",
          "bg_count": 29
          "key": "成田",
          "bg_count": 82
          "key": "千住",
          "bg_count": 93
          "key": "都営",
          "bg_count": 363
          "key": "上野公園",
          "bg_count": 23
          "key": "成田空港",
          "bg_count": 67
          "key": "秋葉原",
          "bg_count": 51
          "key": "集計",
          "bg_count": 64
          "key": "浅草",
          "bg_count": 94
          "key": "区内",
          "bg_count": 104
          "key": "葉",
          "bg_count": 60
          "key": "日間",
          "bg_count": 55
          "key": "江戸",
          "bg_count": 86
          "key": "恩賜",
          "bg_count": 23
          "key": "松坂屋",
          "bg_count": 21
          "key": "千葉",
          "bg_count": 46

悪くない気がする。

結構「上野」感の雰囲がでているかもしれません。

significant .... はそういうものだから当たり前のところもありますが、一文字のものは取り除くとしたらそのまま使えるのでは?と思わせるところがありますね。

linuxコマンドラインスクリプトの参考にしたリンク

http://taichiw.hatenablog.com/entry/2012/04/06/102650

https://qiita.com/kkdd/items/725e53572bc69e4b51b7

https://orebibou.com/2015/07/sedコマンドで覚えておきたい使い方12個/

アンサイクロペディア

https://ansaikuropedia.org/wiki/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8

wikipedia

https://dumps.wikimedia.org/backup-index.html

http://koiroha.blogspot.com/2017/04/how-to-get-wikipedia-dump-as-plaintext.html

http://nonbiri-tereka.hatenablog.com/entry/2015/10/12/104800

参考文献リンク

http://komaken.me/blog/2018/01/16/elasticsearch-aggregationに任意の値を含める/ [Elasticsearch] aggregationに任意の値を含めるhttps://github.com/logstash-plugins/logstash-patterns-core/blob/master/patterns/grok-patterns

*1:※ ja-wiki.xmlアンサイクロペディアの全件データです。

*2:significant_termsと言いましたが、実際はtextにしました