1. HOME
  2. ブログ
  3. IT技術
  4. MapReduceプログラミングモデルをJavaで実装し 日本語テキストの単語出現頻度を求める

MapReduceプログラミングモデルをJavaで実装し 日本語テキストの単語出現頻度を求める

MapReduceプログラミングモデルをJavaで実装し日本語テキストの単語出現頻度を求めてみる

MapReduce とは、簡単に言うと「膨大なデータを処理するためのプログラミングモデル及びその実装」のことです。

もともと MapReduce は、Google社の Jeffrey Dean と Sanjay Ghemawat が執筆した論文に紹介されていました。

現在では、Google だけではなく、多数の大手会社によって導入されています。

一部ではありますが、導入している会社はこんなビッグネームばかりです。

  1. Apache Software Foundation
  2. Cloudera
  3. Hortonworks
  4. IBM
  5. Oracle
  6. Amazon
  7. Microsoft
  8. MapR
  9. Hitachi

最近のビッグデータの時代では、MapReduce が基盤技術のひとつとなっています。

MapReduce の利点

MapReduce の利点の1つとしては、比較的にシンプルな手法で、膨大なデータの並列分散処理が行うことが出来ることです。

MapReduce のプログラミングモデル

MapReduce は、「Mapフェーズ」と「Reduceフェーズ」から成り立っています。

Dean氏と Ghemawat氏の論文では、MapReduce のプログラミングモデルを説明するために、多大のテキストドキュメントにおける単語の出現頻度を求める例が挙げられました

対象となるテキストは、もちろん「英文」です。

このサンプルケースにおいて、MapReduce のプログラミングモデルは以下のような疑似コード(pseudo-code)で実装されました。

疑似コードに基づいて MapReduce プログラミングモデルを実装してみる!

今回は、この疑似コードに基づいて、MapReduce プログラミングモデルを実装し、複数の日本語テキストドキュメントから単語の出現頻度を求めてみたいと思います!

こちらの記事もオススメ!

MapReduce のプログラミングモデルをJavaで実装

対象データは日本語のテキスト文章ですので、日本語の「自然言語処理(Natural Language Processing)ライブラリー」が必要になります。

そこで、今回は使うのは「Kuromoji」という、日本語自然言語処理 Java ライブラリーです。

【Kuromojiダウンロードサイト】
https://github.com/atilika/kuromoji/downloads

Kuromojiの詳細

Kuromoji の詳細については、以下の Atilika のウェーブページをご参照ください!

【Atilika】
https://www.atilika.org/

日本語のストップワードリスト

その他に、日本語の文章から「助詞」や「非常に一般な単語かつ文章の文脈にあまり影響を及ばない単語(stopword)」を取り除くために日本語のストップワードリストも必要です。

これは Github からダウンロードすることが出来ます。

【Github(ストップワードリスト)】
https://github.com/stopwords-iso/stopwords-ja/blob/master/stopwords-ja.txt

開発環境

今回の執筆者の環境は、以下の通りとなっています。

  1. IDE: IntelliJ IDEA
  2. JDK: Oracle Java 8
  3. OS: MacOS Catalina

プロジェクトの構成

MapReduce:Mapフェーズ

「Mapフェーズ」では、inputディレクターから読み込まれた3個の日本語テキストファイルを、Mapper.java の map(String key, String value)  関数に渡します。

  1. 引数 key  は、テキストファイルのファイル名です。
  2. 引数 value  は、テキストファイルの内容です。

文を構造する全ての単語を取得し、トークンとして扱う

まず、regex を用いて、テキスト文章から単語でないものを削除しましょう。

そして、Kuromoji ライブラリーの Tokenizer を適用し、テキスト文章のトークン化(Tokenization)を行います。

つまり、文を構造する全ての単語を取得し、トークン(Token)として扱います

そして、得られた全ての単語を emitIntermediate(String key, Integer value) 関数に渡します。

  1. 引数 key  はひとつの単語です。
  2. 引数 value  は Integer の 1 です。

ストップワードである単語を除く

emitIntermediate(String key, Integer value) 関数では、Mapフェーズの出力(MapOutオブジェクト)が生成されます。

ここで、ストップワードのリストを用いて、ストップワードである単語を除きます

MapOut.javaクラスは String key  と Integer value  の変数から成り立ちます。

変数 key はひとつの単語を格納し、 value は数値の1を格納します。

MapOut.java のコード

MapOut.java のコードは以下のようになります。

Mapフェーズのテキストデータ処理は、Mapper.javaクラスにて実装しました。

MapReduce:Reduceフェーズ

「Reduceフェーズ」では、Mapフェーズの出力(MapOutオブジェクト)を、Reducer.java の reduce(String key, List<Integer> values) 関数に渡します。

reduce(String key, List<Integer> values) 関数の引数 key は、ひとつの単語で、引数 values  は数値1からなるリスト(List[1,1,1,…])です。

MapOut のデータ構造が、 reduce(String key, List<Integer> values) 関数の引数に合わないため、そのままデータを渡すことが出来ません。

ここで、ReduceIn.java の generate(List<MapOut> mapOuts) 関数で MapOut のデータ構造を ReduceIn のデータ構造に変換します。

ReduceIn.java のコード

ReduceIn.java のコードは、以下のようになります。

Reduceフェーズが開始

それから、変換されたデータを reduce(String key, List<Integer> values) に渡して、Reduceフェーズが開始されます。

これによって、各単語の出現頻度をカウントされ、Result が出力されます

Resultクラスは、「key(単語)」と「count(出現頻度)」という2つのメンバーから成り立っています。

Reducer.java と Result.java のコード

Reducer.java と Result.java のコードは、それぞれ以下のようになります。

これで、MapフェーズとReduceフェーズの準備が完了しました!

MapReduce の実行

MapReduce を実行してみましょう!

MapReduceWordFreq.java の main(String[] args) で、日本語テキスト文章の単語出現頻度を求める MapReduce を実行します。

ここで先ず、入力ファイルを TextFileReader で読み込んで、それから Mapper と Reducer を実行します。

MapReduceWordFreq.java のコード

MapReduceWordFreq.java のコードは、次のようになります。

実行結果

=============================
Mapper –> list(key, value)
=============================
NHK:1
大河ドラマ:1
麒麟:1
くる:1
主人公:1
明智:1
光秀:1
所有:1
脇差し:1
名刀:1… 省略
=============================
Mapper –> list(key, value)
=============================
新型:1
コロナ:1
ウイルス:1
感染:1
拡大:1
受け:1
日本:1
政府:1
きょう:1
閣議:1… 省略
=============================
Mapper –> list(key, value)
=============================
北海道:1
札幌:1
市:1
新た:1
7:1
人:1
新型:1
コロナ:1
ウイルス:1
感染:1… 省略
=============================
Reducer(key, values)
=============================
NHK:[1]
大河ドラマ:[1]
麒麟:[1]
くる:[1]
主人公:[1]
明智:[1, 1, 1, 1]
光秀:[1, 1, 1, 1]
所有:[1, 1, 1, 1]
脇差し:[1, 1]
名刀:[1, 1]… 省略
=============================
Reducer Results –> word:count
=============================
刀:1
マカオ:1
市:5
討っ:1
者:2
分:2
万:2
滞在:1
上:1
部分:1
午前:2
成瀬:3
子孫:1
話し:1
くる:1
明智:4
発給:2
14:1
15:1
およそ:3… 省略Process finished with exit code 0

MapReduce の実行は成功しました!

MapReduce を使わずに簡単に求める方法とは?

でも、ちょっと待って。

単語の出現頻度を求める為なら、もっと簡単な方法があるのでは!?

その通りです。

以下のコード(WordFreq.java)で MapReduce を使わずに、より簡単な方法で単語の出現頻度を求めることが出来ます!

しかし、多数のファイルからなる膨大なテキストデータを処理する時に、WordFreq.java のような手法を用いると、処理スピードはマシーンの計算能力に制限されます。

それに対し MapReduce は、その膨大なデータを分割し、分散システム上で並列的に処理しますので、マシーンの数を増やすだけで、データ処理のスピードをどんどん向上させることが出来ます

コードの追加

最後に、本記事の MapReduce 実装に用いた入力テキストファイルを読み込むコード(TextFileReader.java)と、日本語ストップワードファイルを読み込むコード(StopwordReader.java)を追加します。

さいごに

MapReduce プログラミングモデルを実装し、日本語テキストドキュメントから単語の出現頻度を求めてみました!

また、MapReduce を使わずに簡単に求める方法も、併せてご紹介いたしました。

ご自身の環境に合わせて使い分けてみてください!

(株)ライトコードは、WEB・アプリ・ゲーム開発に強い、「好きを仕事にするエンジニア集団」です。
Javaでのシステム開発依頼・お見積もりはこちらまでお願いします。
また、Javaを扱えるエンジニアを積極採用中です!詳しくはこちらをご覧ください。

※現在、多数のお問合せを頂いており、返信に、多少お時間を頂く場合がございます。

こちらの記事もオススメ!

ライトコードよりお知らせ

にゃんこ師匠にゃんこ師匠
システム開発のご相談やご依頼はこちら
ミツオカミツオカ
ライトコードの採用募集はこちら
にゃんこ師匠にゃんこ師匠
社長と一杯飲みながらお話してみたい方はこちら
ミツオカミツオカ
フリーランスエンジニア様の募集はこちら
にゃんこ師匠にゃんこ師匠
その他、お問い合わせはこちら
ミツオカミツオカ
   
お気軽にお問い合わせください!せっかくなので、別の記事もぜひ読んでいって下さいね!

一緒に働いてくれる仲間を募集しております!

ライトコードでは、仲間を募集しております!

当社のモットーは「好きなことを仕事にするエンジニア集団」「エンジニアによるエンジニアのための会社」。エンジニアであるあなたの「やってみたいこと」を全力で応援する会社です。

また、ライトコードは現在、急成長中!だからこそ、あなたにお任せしたいやりがいのあるお仕事は沢山あります。「コアメンバー」として活躍してくれる、あなたからのご応募をお待ちしております!

なお、ご応募の前に、「話しだけ聞いてみたい」「社内の雰囲気を知りたい」という方はこちらをご覧ください。

ライトコードでは一緒に働いていただける方を募集しております!

採用情報はこちら

関連記事

採用情報

\ あの有名サービスに参画!? /

バックエンドエンジニア

\ クリエイティブの最前線 /

フロントエンドエンジニア

\ 世界はお前の手の中に・・・ /

モバイルエンジニア

\ サービスの守り神! /

インフラエンジニア