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

興味深い記事だな

さよならGAFAM:Googleやめてみる→ネット全土崩壊

さよならGAFAM:5社一気にブロック→地獄です

この シリーズは、ほかにもあるぞ。暇に任せて読むといい。

ぐぐるは広告産業。ひたすら広告を貼り出せる電柱のスペースを求めている。そして、その広告をちゃんと見てもらえるように、検索サービスをやってる。

オイラーが移転した先では、電柱を貼紙禁止にしてるんで、ぐぐるはいつまで経ってもよって来ない。 金を生まないHomePageには興味なし。かくしてググルの村八分決定。

こういう深層に至るには、ボーと生きてちゃ駄目だって事ですな。