mongo-hadoop & mahout でドキュメントのクラスタリング(関連付け)
Solrが結構困ったちゃん
全文検索エンジンSolrは便利なのだが、どうもAvailavilityに問題がある様に思う。
いや、環境がPoorなのもあるのだけれども
GCも、PV負荷も、Indexing関連処理も
して無い時間帯なのにクエストが刺さる事が多々ある!
今までは色々なキャッシュを駆使して凌いで来たけど、どうにもこうにも限界なようだ・・・
- Solr クエリキャッシュ
→クエリの結果を一定時間キャッシュする
- Solr フィルタキャッシュ
→別クエリでも共有できる部分は共有する
→そもそもSolrにクエリーを投げない!
精度の問題もあったりするので、コレを期にHadoopで自前で処理してしまおうかと思った。
登場人物
- //www.mongodb.org/">MongoDB:勢いのある(OSS)分散DB。一貫性と分散性(CPシステム)に優れる。
- //code.google.com/p/lucene-gosen/">lucene-gosen:形態素解析ライブラリ。
- //hadoop.apache.org/">Hadoop:言わずと知れた大規模分散処理プラットフォーム。
これが無きゃ始まらない。 - //mahout.apache.org/">Mahout:Hadoop上でkmeansやrandomforestなどの解析系アルゴリズム実装
これ無しじゃHadoop使う気にならない!凄く重要 - //www.10gen.com/presentations/mongodb-tokyo-2012/big-data-analysis-with-mongo-hadoop">mongo-hadoop:普通、HadoopはHDFS上のファイルをInput/Outputするのだが
mongo-hadoopを使うとMongoDBへInput/Output出来る様になる!
HDFS上に重要なファイルを保存して置くのは抵抗があるので重要(HDFSの保全は大変)
作戦1
- 処理したいデータはMongoDBに入っている。
- mongo-hadoop&lucine-gosenで形態素解析しMahoutでVectorize(ベクトル化)してからMongoDBへ書き戻す。
- Mahout&mongo-hadoopでkmenas(canop,fuzzy辺りを試す)かけてMongoDBへ書き戻す。
- mongo-hadoopでインデックス化してMongoDBへ書き戻す。
- PHP(web)からインデックスを参照。
オンライン処理(web)はあくまでMongoDBを参照するだけに出来る。
→今まで問題だったオンライン処理(web)中にSolrへの問い合わせが回避できる
さて、やってみようか!!
挫折
can't convert: org.apache.mahout.math.VectorWritable to BSON
なんてこった!
で、ソースを見る(MongoRecordWriter.java)
if ( x instanceof Writable ){ if ( x instanceof AbstractMapWritable ) throw new IllegalArgumentException( "ERROR: MapWritables are not presently supported for MongoDB Serialization." ); if ( x instanceof ArrayWritable ){ // TODO - test me Writable[] o = ( (ArrayWritable) x ).get(); Object[] a = new Object[o.length]; for ( int i = 0; i < o.length; i++ ) a[i] = (Writable) toBSON( o[i] ); } if ( x instanceof BooleanWritable ) return ( (BooleanWritable) x ).get(); if ( x instanceof BytesWritable ) return ( (BytesWritable) x ).getBytes(); if ( x instanceof ByteWritable ) return ( (ByteWritable) x ).get(); if ( x instanceof DoubleWritable ) return ( (DoubleWritable) x ).get(); if ( x instanceof FloatWritable ) return ( (FloatWritable) x ).get(); if ( x instanceof LongWritable ) return ( (LongWritable) x ).get(); if ( x instanceof IntWritable ) return ( (IntWritable) x ).get(); // TODO - Support counters }
そうだよね・・・
当然ながらmongo-hadoopはHadoop実装のWritableにしか対応してない!
(VectorWritableはMahoutのモノ)
springでランタイムパッチも出来るかもしれないが
Hadoop上での挙動が謎だし、そもそもmongo-hadoopを直す気力が無いので
今回は諦める。。
諦めてHDFS使う作戦1
- 処理したいデータはMongoDBに入っている。
- mongo-hadoop&lucine-gosenで形態素解析しSequenceFileとしてHDFSへ書き出す。
- Mahout seq2parseでVectorize(ベクトル化)する。→ HDFS上にVectorデータが出来る
- Mahout canopy&kmeans (fuzzyの方が使い易いかも・・・)。→ HDFS上にClusterデータが出来る。
- mongo-hadoopでインデックス化してMongoDBへ書き戻す。
- PHP(web)からインデックスを参照。
これでも、
- 重要なデータはHDFSに置かない。
- Solr使わない。
は達成できる。
実装中・・・