秘密を教えてしまう検索
検索のアクセス権とは、人が読んでよいものだけを見つけられることです。鮮度とは、削除された文書や古い文書が索引から消えることです。検索は文書を別の場所に写し、写しは元の規則を知らないので、どちらも大切です。
学生が「休暇 日程」を検索して、給与のページを受け取ります。あるいは、削除した規則がまだ答えます。
このレッスンのゴール
メモ
検索を各人が見てよい範囲にとどめ、削除や新しい版を索引まで届かせることができる。
キーワード
| ことば | いみ |
|---|---|
| アクセスフィルター | 読んでよいものだけを残す規則 |
| グループ | アクセスを共有する人の、名前の付いた集まり |
| 古い写し | 現在の版より古い写し |
| バージョン | 文書が変わるたびに増える番号 |
| 削除の印 | 何かが削除された記録 |
| 漏えい | 見てはいけない人に見せてしまうこと |
学生が入力するセルは、このプレビューでは空白です。
順位付けの前に絞る、後ではない
各断片は、読んでよいグループを持ちます。メタデータの一種です。問い合わせのとき、検索はまず質問者のグループが許す断片だけを残し、そのあとで上位 k 個を取ります。
上位 k 個のあとで絞ると、二重に失敗します。隠すページが一枠を取り、人は本来より少ない結果しか得られません。しかも「3 件中 2 件非表示」は、そのページの存在を教えてしまいます。
例: 学生の aoi が休暇の日程を探す
| やり方 | aoi への結果 | 起きる問題 |
|---|---|---|
| 上位 2 件のあとで絞る | e1 | 給与のページが一枠を取り、そのあと隠された |
| 上位 2 件の前に絞る | e1, e3 | なし |
| 前に絞り、古い写しを除く | e1 | 古い写し e3 が消える |
学生が入力するセルは、このプレビューでは空白です。
削除は索引まで届かせる
索引は、各文書の自分用の写しを持っています。元のファイルを削除しても、この写しには触れないので、古いテキストが答え続けます。文書のすべての断片を、索引と回答のキャッシュから、同じ手順で削除します。
文書の変更も同じ問題です。各断片にバージョンを付け、文書を更新するときに、現在より古い断片を捨てます。
よくある間違い
注意
元のファイルを削除すれば検索からも消えると考える人がいます。索引が写しを持っているので、テキストはまだ見つかります。索引からも削除し、削除したページの一文を検索して確かめます。
権限付き検索を書く(1)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const entries = [' ' { id: \"e2\", doc: \"給与\", groups: [\"職員\"], version: 1, text: \"賞与 休暇 日程 管理職\" },' ' { id: \"e4\", doc: \"シフト\", groups: [\"職員\"], version: 1, text: \"休暇 中 勤務 者\" },' ' { id: \"e1\", doc: \"ハンドブック\", groups: [\"職員\", \"学生\"], version: 2, text: \"休暇 日程 学期\" },' ' { id: \"e3\", doc: \"ハンドブック\", groups: [\"職員\", \"学生\"], version: 1, text: \"旧 休暇 日程\" },' '];' 'const current = { ハンドブック: 2, 給与: 1, シフト: 1 };' 'const aoi = { name: \"aoi\", groups: [\"学生\"] };' > access1.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
権限付き検索を書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function allowed(e, user) { return e.groups.some(function (g) { return user.groups.includes(g); }); }' 'function score(e, q) { return q.filter(function (w) { return e.text.split(\" \").includes(w); }).length; }' 'function top(list, q, k) {' ' return list.filter(function (e) { return score(e, q) > 0; })' ' .sort(function (a, b) { return score(b, q) - score(a, q); })' ' .slice(0, k);' '}' 'function ids(list) { return list.map(function (e) { return e.id; }).join(\" \") || \"なし\"; }' >> access1.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
権限付き検索を書く(3)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const q = [\"休暇\", \"日程\"];' 'function mine(list) { return list.filter(function (e) { return allowed(e, aoi); }); }' 'console.log(\"上位 2 件のあとで絞る:\", ids(mine(top(entries, q, 2))));' 'console.log(\"上位 2 件の前に絞る:\", ids(top(mine(entries), q, 2)));' 'const fresh = entries.filter(function (e) { return e.version >= current[e.doc]; });' 'console.log(\"さらに古い写しを除く:\", ids(top(mine(fresh), q, 2)));' 'const left = entries.filter(function (e) { return e.doc === \"ハンドブック\" ? false : true; });' 'console.log(\"ハンドブックを削除したあと、aoi が見つけるもの:\", ids(top(mine(left), q, 2)));' >> access1.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
実行してフィルターを比べる
docker exec -w /home/node/project agent node access1.jsここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
これは練習用の代用品です
索引は四つのエントリーのリストで、人は名前とグループです。語はスペースで区切ってあります。本物は、ログイン中のアカウントに基づいて検索エンジンの中で絞り、削除はその検索エンジンへの本物の呼び出しです。
Run はモデルを呼びません。規則は同じで、先に絞り、あらゆる場所で削除します。
Run の出力
| 行 | 結果 |
|---|---|
| 上位 2 件のあとで絞る | e1 |
| 上位 2 件の前に絞る | e1 e3 |
| さらに古い写しを除く | e1 |
| ハンドブックを削除したあと、aoi が見つけるもの | なし |
学生が入力するセルは、このプレビューでは空白です。