中年engineerの独り言 - crumbjp

LinuxとApacheの憂鬱

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:普通、HadoopHDFS上のファイルをInput/Outputするのだが
mongo-hadoopを使うとMongoDBへInput/Output出来る様になる!
HDFS上に重要なファイルを保存して置くのは抵抗があるので重要(HDFS保全は大変)

作戦1

  1. 処理したいデータはMongoDBに入っている。
  2. mongo-hadoop&lucine-gosenで形態素解析しMahoutでVectorize(ベクトル化)してからMongoDBへ書き戻す。
  3. Mahout&mongo-hadoopでkmenas(canop,fuzzy辺りを試す)かけてMongoDBへ書き戻す。
  4. mongo-hadoopでインデックス化してMongoDBへ書き戻す。
  5. 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-hadoopHadoop実装のWritableにしか対応してない!
(VectorWritableはMahoutのモノ)

springでランタイムパッチも出来るかもしれないが
Hadoop上での挙動が謎だし、そもそもmongo-hadoopを直す気力が無いので
今回は諦める。。

諦めてHDFS使う作戦1

  1. 処理したいデータはMongoDBに入っている。
  2. mongo-hadoop&lucine-gosenで形態素解析しSequenceFileとしてHDFSへ書き出す。
  3. Mahout seq2parseでVectorize(ベクトル化)する。→ HDFS上にVectorデータが出来る
  4. Mahout canopy&kmeans (fuzzyの方が使い易いかも・・・)。→ HDFS上にClusterデータが出来る。
  5. mongo-hadoopでインデックス化してMongoDBへ書き戻す。
  6. PHP(web)からインデックスを参照。

これでも、

  • 重要なデータはHDFSに置かない。
  • Solr使わない。

は達成できる。

実装中・・・