前提
形態素解析を実装したいので、Kuromoji というライブラリを導入しました。
Kuromojiでかんたん形態素解析 という記事のおかげもあり、基本的な動作は確認済みです。
目的
目的はこの辞書データの効率的な参照です。
上記リンクに ディクショナリーフォルダ1式(辞書データです) とあるように、Kuromoji は zip ファイルを辞書として参照するのですが、これがなかなか大きなデータでして、効率的に(サーバー負荷を少なく)扱う方法はないかと考えている次第です。
考えていること
考えていること1
1回読んだ zip ファイルを何度も読むことは避けたいと思い、IndexedDB への保存を試みました。
しかし、Kuromoji は kuromoji.builder()
なる関数によって辞書を参照するようで、その引数に指定できる値が辞書へのURLだけのようでした。
つまり、IndexedDB へ保存しても、それを kuromoji.builder()
のために参照する方法がなさそう、ということです。
もしこの方法をご存じの方がいらっしゃったらご教示いただけますと幸いです。
考えていること2
上述したように IndexedDB への保存という案では実装できなそうだ、と悩んでいたのですが、そもそももしかして、zip ファイルを読んだ際にもキャッシュって効くのでしょうか?だとしたら IndexedDB への保存など不要?
実際に以下のような計測コードを試したところ、1回目と2回目で半分くらいの時間になったので、どうやら zip ファイルにもキャッシュが効くのか?と思えたのですが、その確証が得れません。
JavaScript
1(() => { 2 const DICT_PATH = "./dict"; 3 4 // 長文として https://www.aozora.gr.jp/cards/000148/files/789_14547.html から『吾輩は猫である』など 5 const story = `長文`; 6 7 const ids = []; 8 const names = []; 9 10 // 処理開始の時間を記録 11 console.time("Kuromoji Processing Time"); 12 13 // Kuromoji 14 kuromoji.builder({ dicPath: DICT_PATH }).build((err, tokenizer) => { 15 if (err) { 16 console.error("Tokenizer error:", err); 17 return; 18 } 19 20 const tokens = tokenizer.tokenize(story); // 解析データの取得 21 tokens.forEach((token) => { // 解析結果を順番に取得する 22 console.log(token); 23 }); 24 25 // 処理終了の時間を記録 26 console.timeEnd("Kuromoji Processing Time"); 27 }); 28 29})();
どうなのでしょうか?もしキャッシュが効くのなら、特に何もしなくてもできる限り効率的な実装がなされていると考えていいのでしょうか?
確認したこと
Kuromoji は CDN で下記リンクから読んでおりまして、
https://cdn.jsdelivr.net/npm/kuromoji@0.1.2/build/kuromoji.js
これを確認すると、辞書データの扱いに際しては zlib.js というライブラリ を使っているようです。
ただこのライブラリが Kuromoji の辞書データである zip ファイルを解凍し、キャッシュし、よしなにしてくれるのか?までは調査、読解するスキルがありませんでした。
以上です。なんだかいまいちまとまっていない文章になってしまいましたが、質問としては Kuromoji の辞書データを効率的に(サーバー負荷を少なく)扱う方法か、またはそもそもそんな方法を模索しなくてもキャッシュされているから何もしなくてもいいのか、という2点になります。
よろしくお願い致します。
補足
下記 JavaScript のように
・初回訪問した際は initializeTokenizer()
を実行して IndexedDB に保存
・形態素解析の際は analyzeText()
で解析
ということが出来るかも?と思ったのですが、初回訪問の initializeTokenizer()
の時点で blob:https:/example.com/[UUID]/base.dat.gz
など各種辞書データの GET ができないとコンソールにエラーが出まくってしまい、断念しました。(この方針も、そもそもブラウザが1回読んだ zip ファイルを自動でキャッシュしてくれるのであれば不要ですが。)
JavaScript
1/*---------------------------------------------------------------------------------------------------- 2 3 File: kuromoji-manager.js 4 Path: /assets/js/module/lib/kuromoji-manager.js 5 Description: Kurromoji の管理モジュール 6 7----------------------------------------------------------------------------------------------------*/ 8 9let tokenizer; 10const DB_NAME = "kuromojiCacheDB"; 11const STORE_NAME = "dictionaryStore"; 12const DICT_PATH = "./dict"; 13 14/*-------------------------------------------------- 15 解析 16--------------------------------------------------*/ 17 18// 形態素解析を実行 19function analyzeText(string) { 20 21 if (!tokenizer) { 22 const contents = "Tokenizer is not ready yet. Please wait..."; 23 console.log('analyzeText() contents', contents); 24 return; 25 } 26 27 const tokens = tokenizer.tokenize(string); 28 const contents = tokens.map(token => 29 `表層形: ${token.surface_form}, 品詞: ${token.pos}, 基本形: ${token.base_form}` 30 ).join("\n"); 31 32 console.log('analyzeText() contents', contents); 33} 34 35/*-------------------------------------------------- 36 初期化 37--------------------------------------------------*/ 38 39// IndexedDBに辞書データを保存 40async function saveDictionaryToDB(data) { 41 const db = await openIndexedDB(); 42 const transaction = db.transaction(STORE_NAME, "readwrite"); 43 const store = transaction.objectStore(STORE_NAME); 44 store.put(data, "kuromoji_dict"); 45 console.log("辞書データをIndexedDBに保存しました。"); 46} 47 48// IndexedDBから辞書データを取得 49async function getDictionaryFromDB() { 50 const db = await openIndexedDB(); 51 const transaction = db.transaction(STORE_NAME, "readonly"); 52 const store = transaction.objectStore(STORE_NAME); 53 return store.get("kuromoji_dict"); 54} 55 56// IndexedDBを開く(または作成) 57function openIndexedDB() { 58 return new Promise((resolve, reject) => { 59 const request = indexedDB.open(DB_NAME, 1); 60 request.onupgradeneeded = event => { 61 const db = event.target.result; 62 if (!db.objectStoreNames.contains(STORE_NAME)) { 63 db.createObjectStore(STORE_NAME); 64 } 65 }; 66 request.onsuccess = () => resolve(request.result); 67 request.onerror = () => reject(request.error); 68 }); 69} 70 71// トークナイザーを初期化 72async function initializeTokenizer() { 73 console.log("辞書データをロード中..."); 74 75 const cachedData = await getDictionaryFromDB(); 76 if (cachedData) { 77 console.log("IndexedDBから辞書データを読み込み中..."); 78 // 辞書データをBlob URLに変換 79 const dicBlobURL = URL.createObjectURL(new Blob([cachedData])); 80 81 console.log('initializeTokenizer() dicBlobURL: ', dicBlobURL); 82 83 tokenizer = await buildTokenizer(dicBlobURL); // build関数をPromise化して利用 84 } else { 85 console.log("CDNから辞書データを取得中..."); 86 tokenizer = await buildTokenizer(DICT_PATH); 87 // 辞書データをIndexedDBに保存する処理(省略) 88 } 89} 90 91// Kuromojiのビルダー関数をPromiseでラップする 92function buildTokenizer(dicPath) { 93 return new Promise((resolve, reject) => { 94 kuromoji.builder({ dicPath: dicPath }).build((err, tokenizer) => { 95 if (err) { 96 reject(err); 97 } else { 98 resolve(tokenizer); 99 } 100 }); 101 }); 102} 103 104/*-------------------------------------------------- 105 export 106--------------------------------------------------*/ 107 108export default { 109 analyzeText, 110 initializeTokenizer, 111}

回答1件
あなたの回答
tips
プレビュー