Redisで全文検索
台風一過で天気が良いのでnodeとRedisのSETを転置インデックスに使った全文検索を作った.
wikipediaのタイトル一覧(約100万件)をtri-gramで分解しRedisに突っ込んだ結果,約800万件の転置インデックスを挿入するのにおよそ3分,サイズは700MB程度だった.
同じようなことをmongodbでもできるが挿入速度ではRedisが有利だろう.
転置インデックス作成
const redis = require('redis'); const byline = require('byline'); const fs = require('fs'); const client = redis.createClient(); const ngram = function(str, n) { n = n ? n : 3; var grams = []; for(var i = 0; i <= str.length - n; i++) { grams.push(str.substr(i, n).toLowerCase()); } return grams; }; if(process.argv.length < 3) { process.stderr.write('argv error\n'); process.exit(1); } var rs = fs.createReadStream(process.argv[2], { encoding: 'utf8' }); var ls = byline.createLineStream(rs) var titles = []; var iis = []; var index = 0; var ic = 0; ls.on('data', function (data, line) { titles.push('key-' + index); titles.push(data); var grams = ngram(data); // Tri-gram for(var i = 0; i < grams.length; i++) { iis.push(['sadd', grams[i], index]); } index++; if(titles.length > 100000) { ls.pause(); client.mset(titles, function(err, res) { ls.resume(); }); titles = []; } if(iis.length > 500000) { ic += iis.length; ls.pause(); client.multi(iis).exec(function(err, res) { ls.resume(); }); iis = []; } }); ls.on('end', function () { client.mset(titles, function(err, res) { client.multi(iis).exec(function(err, res) { ic += iis.length; console.log(ic); client.end(); }); }); });
検索
const redis = require('redis'); const client = redis.createClient(); const byline = require('byline'); const fs = require('fs'); const ngram = function(str, n) { n = n ? n : 3; var grams = []; for(var i = 0; i <= str.length - n; i++) { grams.push(str.substr(i, n).toLowerCase()); } return grams; }; const search = function(str, n) { var grams = ngram(str, n); var t = new Date; client.sinter(grams, function(err, res) { res = res.map(function(e) { return 'key-' + e; }); client.mget(res, function(err, res) { console.log(res); console.log('----------------------------------------'); console.log('' + res.length + 'results(' + (new Date - t) + 'ms)'); client.end(); }); }); }; if(process.argv.length < 3) { process.stderr.write('argv error\n'); process.exit(1); } search(process.argv[2]);