WSLで私設のググル検索アプリ
『春を少し、分けてもらえませんか』
こんな気取った言い方を田舎の人はしないだろう。おばちゃん、びっくりして警戒するぞ。 ならば、『たんとな ふきっ玉、喰わんなら 貰えんか もし』
何時もの散歩道で、庭先に生えてる蕗が気になって気になってしょうがない。もう数年、春が巡ってくる度に指を喰わてみてるんだけど、家人が摘み草した様子は全く無し。
ならば、オイラーが勝手につみ草する? それって窃盗だろう、その前に住居不法侵入か。 そう思うなら、堂々と玄関から、おたの申すと行けばいいものを。そこまで厚かましくないぞ。
が、今朝は家人のおばちゃんが、庭の手入れをしてたものだから、これはチャンスと思った次第。 そんな事で、許可を貰ったのさ。おうちでは食べないんですかって聞くと、爺様は余り食べないんで、気が向いた時に、ちょっと蕗味噌するぐらいらしい。年寄り夫婦だけだと、そんなに必要無いものね。
おばちゃんが、それ取れやれ取れって協力してくれたおかげで、あっという間に、山が出来た。 こうして、2時間後の昼食には、いの一番で、春を噛みしめましたよ。幸せ。
夜は、天ぷらかな? 期待だな。
googleの代わり
オイラーがホームページを移転してから、ググル様のロボットが一度もやって来た素振りが無い。そんなの別に、どうでもいいじゃん。
ちょいと困る事が有るんだ。過去に書いた記事を後から検索したい時、ググルを使っていたからね。いわゆるサイト内検索ね。
site:https://hamesspam.sakura.ne.jp key1 key2
みたいにすると、指定したサイト内から、keyを探してくれる。
これが出来ないと、困る。
だったら、自前で検索システム作れよ。昔、盛んに 全文検索システム Namazuにお世話になったろう。古いなあ。今なら、MySQLあたりが検索エンジン機能を持ってるのかな。よう知らん。ぐぐるに頼りっきりだからね。
だったら、自分の分ぐらいは、自分で何とかしなさいよ。DIYですよ。
そんな訳で、grepが日本語を受け付けてくれるか、簡単に調査してみた。
sakae@atom:~/piki/old$ grep ワレット */*.html hes2016/160814.html:<p>で、商品権は、カードに入れてくれるそう。ワレットカードって知ってます? hes2016/160814.html:<p>そんなワレットカードって、ずばり財布って意味なのね。オイラーは、小銭 : hes2016/160817.html:<p>ワレットからカタログが送られてきた。ポイントで購入出来ますからどうぞってね。</p>
Windows10に入れているWSLで試したら、それなりに出てきたんだ。
オイラーはWSLで、debianの最小限の奴にmakeとw3mを足しただけのシステムにしてるんだけど、grepだけで、検索出来た。
ならば、これを発展させればいいな。30年前の素朴な検索システムね。
仕様
Windows上に保管してる生htmlを対象に、grepで検索する。keyは複数指定可能として、AND検索とする。出力は、htmlなファイル名とする。以上。
schemeのRnRSより、簡単な仕様書だな。検索語が含まれるhtmlなファイル名さえ得られれば、後はw3mするだけですから。
対象ファイルの配置は、下図。この間Webの引っ越しをした時の残骸とも言うものだ。
sakae@usvr:~/piki$ tree -d . ├── hes2019 └── old ├── hes2009 │ └── PNGS : ├── hes2017 └── hes2018
年毎にdirを作り、その中に index.htmlとyymmdd.html(複数個)を配置。本年度以外は、oldの中に移動させてる(これが引っ越し時のごみに相当)。
年毎に、大体60個ぐらいづつ増加してく。一ファイルの大きさは、500行、30Kbyteぐらい。文字コードは、UTF-8。ざっくり、10年分で15Mぐらいになるだろう。
開発は、直接Windows上のWSLでやってもいいんだけど、もしファイルを消してしまうような事が有ると悲しいので、ウブ上にコピーを取って、そこで行う。
初版
とっても素朴なやつ。
#!/bin/sh key='NetBSD' for f in */*.html old/*/*.html do grep -l $key $f done
書いては消し、書いては消すの連続だと思うので、emacsのshellscript-modeのC-c C-xと併用して、実行させる。
気になるのは、検索時間。ぐるるだと、0.5秒ぐらいだけど、せいぜい待てるのは3秒ぐらいかな。
sakae@usvr:~/piki$ time ./zg.sh | wc 73 73 1734 real 0m0.558s user 0m0.405s sys 0m0.143s
600個の原稿中、1割以上は、NetBSDに言及してるな。検索時間もまあまあ。待て、安心するな。最終ターゲットは、Windows上のWSLだぞ。そこで確認してみろ。
sakae@atom:/mnt/c/mine/piki$ time ./zg.sh | wc 73 73 1734 real 0m10.397s user 0m0.422s sys 0m4.375s
WSLが遅いって証拠が出てきたな。ひょっとして初回はキャッシュに乗らないから? 何度実行しても、10秒前後をふらふらしてる。はて、困ったわい。 前のワレット検索の時は、こんなに時間がかからなかったと思う。何が違う?
fork 回避版
初版は素朴に、ファイルを一つづつ検索してた。その度にgrepが起動される。無駄じゃん! 検索したいファイルを多数集めて、一気に検索させよう。度々登場してるxargsを使って。
#!/bin/sh key='NetBSD' find . -name '*.html' | xargs grep -l $key >res cat res rm -f res
検索してkeyが含まれているファイルをresって結果ファイルに残した。そしてそれを表示した後、削除してる。これ、将来への布石。
sakae@usvr:~/piki$ time ./zg.sh | wc 73 73 1880 real 0m0.013s user 0m0.011s sys 0m0.004s
ウブ上で激速になった。
sakae@atom:/mnt/c/mine/piki$ time ./zg.sh | wc 75 75 1903 real 0m0.234s user 0m0.016s sys 0m0.141s
つられて(?)、WSL上でも速くなった。結果数が異なるのは、Windows上には、他のhtmlファイルが有る為です。最終結果を見れば、対象外って事が直ぐに判別出来るので、気にしない。これを 除去しようなんて事を考えると、本筋を見失う。
後は、絞り込まれたリストファイルから、第二、第三(あれば)のkeyで検索してくのかな。
VerUP
次は、第二keyとして、qemuを指定してみた版。意味的には、NetBSDでqemuした経験が有るかと、問うものだ。いや、qemu上にNetBSDを入れたって事かな。
#!/bin/sh key='NetBSD' find . -name '*.html' | xargs grep -l $key >res keyN='qemu' grep -l $keyN `cat res` > res cat res | sort -r rm -f res
ウブ上での結果。
sakae@usvr:~/piki$ time ./zg.sh | wc 13 13 337 real 0m0.015s user 0m0.008s sys 0m0.010s
先ほどは73個あったのが、今度は13個に絞りこまれた。ここまでくれば、安心してウブ上で開発を進められるな。なお、バッククォートで、結果のリストファイルをcatしてるけど、これは、grepの検索対象ファイルを、その場に展開する為だ。
実験コード
ここまでて、検索の主要部分は書けたと思う。次は、引数を受け取ってそれを処理する部分を組み込む作業になる。いきなり組み込んじゃうとテストが大変になるので、引数処理を抜き出した、実験コードをやっておく。
sakae@usvr:~/piki$ cat test.sh #!/bin/sh if [ $# -eq 0 ]; then echo "Usage: $0 key ..." exit 1 fi echo "frst: $1" shift for keyN do echo "Next: $keyN" done echo "RESULT"
最初のifは、引数が無かった場合。使い方を説明して終了。echo "fast $1"の部分は、最初の引数の処理。続くshiftで、引数を一つづらす。この時点で、最初の引数は、忘れさられてしまう。最初の引数だけ、特別扱いしたいのだ。
次のfor文は、引数をkenNに取り込んで処理。echo "Next: $keyN"がその部分。次々と注目引数を取り上げてくれ、引数が無くなるとforを終了。
最後は、結果出力を模したものだ。
sakae@usvr:~/piki$ ./test.sh Usage: ./test.sh key ... sakae@usvr:~/piki$ ./test.sh aaa frst: aaa RESULT sakae@usvr:~/piki$ ./test.sh aaa bbb frst: aaa Next: bbb RESULT sakae@usvr:~/piki$ ./test.sh aaa bbb ccc frst: aaa Next: bbb Next: ccc RESULT
コードに色々な個数の引数を与え、挙動確認。どうやら、大丈夫そう。
Bug
ここまでを組み込んで、テストしてみた。
sakae@usvr:~/piki$ ./zg.sh Usage: ./zg.sh key ... sakae@usvr:~/piki$ ./zg.sh NetBSD | wc 73 73 1880 sakae@usvr:~/piki$ ./zg.sh NetBSD qemu | wc 13 13 337 sakae@usvr:~/piki$ ./zg.sh AhoManukePoor | wc 0 0 0 sakae@usvr:~/piki$ ./zg.sh AhoManukePoor foobarbaz | wc いつまでたっても、終了しない。
file sizeがZEROか確認する -s file を組み込んだぞ。
sakae@usvr:~/piki$ ./zg.sh AhoManukePoor foobarbaz | wc 0 0 0 sakae@usvr:~/piki$ ./zg.sh qemu AhoManukePoor foobarbaz | wc 0 0 0
完成版かな
#!/bin/sh if [ $# -eq 0 ]; then echo "Usage: $0 key ..." exit 1 fi find . -name '*.html' | xargs grep -l $1 >res shift for keyN do if [ ! -s res ]; then rm -f res exit 0 fi grep -l $keyN `cat res` > res done cat res | sort -r rm -f res
これをたたき台に、機能の追加が待ってるぞ。例えば
sakae@usvr:~/piki$ ./zg.sh debian | wc 152 152 3915 sakae@usvr:~/piki$ ./zg.sh Debian | wc 113 113 2930
大文字/小文字の区別をどうするかとか(これは変更が簡単)、表記のゆれをどうするかだ。 ゆれってのは、例えば何かを買ったって場合、その場の気分で、購入、入手、買ったと色々ある。
そこまで、きちんとやろうとすると、ぐぐるになっちゃうよ。ググルは検索結果に手心を加えていないか? SEOと称して勝手にランク付けてるし、村八分もあると聞く。それに対して、今回の作は、ソース公開で、公平無私の完全全文検索ですよ。
ぐぐるで何を検索してたか全部おみとうし。それがいやなら、 DuckDuckGoを使いましょう。あなたのデータが売り渡される事はありません、と謳っている。中の人はどうやって運営してるのだろう?
大人仕様へ変更
上の奴をちょっと使ってみて、失望した。出てきたファイル名をコピーして、w3mに喰わせるって、中坊までだよね。目の前に列挙したファイルが有るなら、自動的にブラウザーに渡してよね。即改善。
#!/bin/sh BR='' if [ "X$1" = "X-w" ]; then BR='w3m -N' shift fi if [ $# -eq 0 ]; then echo "Usage: $0 [ -w ] keyword ..." exit 1 fi find . -name '*.html' | xargs grep -i -l $1 >res shift for keyN do if [ ! -s res ]; then rm -f res exit 0 fi grep -i -l $keyN `cat res` > res done if [ 'X' != "X$BR" ]; then $BR `cat res | sort -r | head -10` else cat res | sort -r | cat -n fi rm -f res
改善ついでに、大文字/小文字のどちらでもHitするように、-iを追加した。おかげで、少々遅くなった。どちらを選ぶかは、好みの問題だな。
ブラウザーを使いたい場合、第一引数に -w を指定する。そうすると、検索結果の冒頭から10個をTAB機能で開いてくれる。10個ってのは、安全弁の積り。
最初、-w無しで検索して、絞り込めたと思ったら、-wを付けて閲覧って流れね。
ああ、w3mのTABオペレーション関係のキーバインドをあげておく。
Tab Operations T Open a new tab (with current document) (NEW_TAB) C-q Close tab (CLOSE_TAB) } Switch to the next tab (NEXT_TAB) { Switch to the previous tab (PREV_TAB) ESC-t Pop up tab selection menu (TAB_MENU) <NOT ASSIGNED> Move right along the tab bar (TAB_RIGHT) <NOT ASSIGNED> Move left along the tab bar (TAB_LEFT)
お前、脳容量少ないんだから、波カッコで、波に乗れぐらいを覚えておけ。並みな脳味噌の連想記憶術だな。
オイラーは、やる積りないけど、firefoxだと -privateと -new-tab URL あたりを併用出来るみたいだぞ。拡張は容易だろう。
speed test
最終的なスピードチェックをしておくか。最初は、Windows
sakae@atom:/mnt/c/mine/piki$ time ./zg.sh qemu-arm pi > /dev/null real 0m3.411s user 0m0.047s sys 0m0.344s sakae@atom:/mnt/c/mine/piki$ time ./zg.sh qemu-arm pi > /dev/null real 0m0.184s user 0m0.016s sys 0m0.141s
どうしても、初回はデータがキャッシュに載っていないので時間がかかる。2回目からは、十分な許容時間内で収まる。次は、参考までにウブ上で実行。
sakae@usvr:~/piki$ time ./zg.sh qemu-arm pi >/dev/null real 0m0.291s user 0m0.006s sys 0m0.088s sakae@usvr:~/piki$ time ./zg.sh qemu-arm pi >/dev/null real 0m0.027s user 0m0.004s sys 0m0.014s
やはり、1桁速いな。
参考に、w3m画面の冒頭部分。
sakae@atom:/mnt/c/mine/piki$ ./zg.sh -w 電池 ipad [ libsvm ][ dc ][ psn ][ hugs -> ghc ][ Nim ] [ 次は何? ][ 12.04, 14.04 LTS ][ ipad ][GaucheとかSECDとか] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ dc 女房にせかされて、ipad用のカバーを買いに行ってきた。ipadを買った時に同時に購入 したものだ。イタリア製とかで、6000円ぐらいしたと思う。 :
鍵カッコ内にタイトルが出てくるんだけど、これを見ると、関係なさそうな所で、言及してるな。やはり、こういう文明の利器は、もっと早くに自作しておくべきだったな。
etc
興味深い記事だな
この シリーズは、ほかにもあるぞ。暇に任せて読むといい。
ぐぐるは広告産業。ひたすら広告を貼り出せる電柱のスペースを求めている。そして、その広告をちゃんと見てもらえるように、検索サービスをやってる。
オイラーが移転した先では、電柱を貼紙禁止にしてるんで、ぐぐるはいつまで経ってもよって来ない。 金を生まないHomePageには興味なし。かくしてググルの村八分決定。
こういう深層に至るには、ボーと生きてちゃ駄目だって事ですな。