タグ: MySQL を抽出しています。
Total: 60

MySQL,fulltextインデックス,Ngram化のまとめ。

ブログ | 2009/9/30 00:46
少し説明的に。
MySQLには、fulltextという全文検索用のインデックスがあります。
ただ、日本語は単語単位で区切られていないので、なんらかの方法で区切る必要があります。区切り方には、形態解析で区切る方法と、意味なんて考えずに1文字とか2文字とかで区切っていくNgramという方式があります。

(あ、その前に、検索対象が数万件くらいなら、「REGEXP」で検索するのがいいと思います。速いし、おそらく厳密だし。)

で、今までは形態解析の方でやってました(mecabなるものを利用)。
ただ、このインデックス化は、「アイスクリーム」を検索したい時に、インデックスに「アイスクリーム」しかないと、「アイス」という検索ではヒットしないというところが難点でした。

初期導入時は、、なんとなく意味で区切った方がインデックス文字列が少なくていいし、優れているのではないかというのが選択動機だったと思います。

さて、Ngram化。

1) まずインデックス文字列の作り方。PHPです。
function ngramIndex($str,$wlen){
 $str = preg_replace('/[\r\n  ]/u','',$str);
 $len = mb_strlen($str);
 $n = array();
 for($i=0; $i < $len; $i++){
   for($a=1; $a <= $wlen; $a++){
     $n[] = mb_substr($str,$i,$a);
   }
 }
 $n = array_unique($n);
 return $n;
}

$str がNgram化したい文字列。
$wlen は、何文字までインデックス化するか(僕は、5にしてみた)

で、配列が返ってくるので、
$str = ngramIndex($str,5);
$str = mysql_real_escape_string(implode(' ',$str));
こんな感じで、$strをMySQLにインサートします。

2) 検索文字列の作り方。PHPです。
function ngram($str){
 $len = mb_strlen($str);
 if($len > 5){
   $n[] = mb_substr($str,0,5);
   if($len > 10){
     for($i=5; $i <= $len-5; $i++){
       if($i%5 == 0){
         $n[] = mb_substr($str,$i,5);
       }
     }
   }
   $n[] = mb_substr($str,-5,5);
   $n = array_unique($n);
 }else{
   $n[] = $str;
 }
 return $n;
}
こんなことにしました。

「マルボロ」-> 「マルボロ」
「クリーニング」-> 「クリーニン, リーニング」
「トールラテで腹下ルのです」-> 「トールラテ, で腹下ルの,下ルのです」

このように配列が返ってくるので、これを展開して、
SELECT ~~~~ WHERE MATCH (ngram) AGAINST ('+クリーニン +リーニング' IN BOOLEAN MODE) ~~~
こんなクエリーにセット。

実際は、複数単語で、AND、OR、除外やらという検索をさせるから、そのあたりはグルグリ関数を書きました。

さて、結果はいかに。今、ポストマップのインデックスを再作成中。
現在、482,436件くらいのデータのようです。
http://postmap.org/list

Rottelも後日、変更していきます。
▼追記 2009/9/30 10:36
5文字までやってたら、longtext型の4294967295byteを超えてエラーで止まった。とりあえず4文字にして、insertする文字数をちゃんと容量内にするように書いて継続。

インデックス作りはもう少し研究が必要だ。
▼追記 2009/9/30 11:44
あー、インデックスづくりで、遅延だ、遅延だ。
▼追記 2009/9/30 15:15
インデックスづくりは休み休みやろう。

...
コメントの検索って、あれ使ってるのかな。
▼追記 2009/10/1 03:29
インデックス作りをなめてた。
朝までに終わるかな・・・。

ポストが終わったら、電話やって、Rottelに行こう。
▼追記 2009/10/2 00:29
なんか、検索スピードが納得いかない。
ヒット件数が少ないと速いみたいだけれど。

インデックスが大きすぎるのが原因のような気がするので、3文字に減らしてみる。
▼追記 2009/10/2 03:05
インデックス更新を回して寝る。
いろんなサイトでDBが遅延してしまいますが、すみません。(投稿したものがすぐに出てくなかったりすると思います)

朝までに終わらない気もする。
▼追記 2009/10/2 19:08
200件インデックス作成したら、30秒スリープしてDBの同期を待つ。これでいい感じ。FULLTEXTインデックスの更新はなかなか遅いらしく、テストするのも何かと大変だ。

leopardサーバー構築メモ20090821

ブログ | 2009/8/22 00:40
OSX 10.5.8
Apache 2.2.11
MySQL 5.0.84
PHP5.3.0

[webmin]
http://www.webmin.com/download.html
cd /Applications/webmin-1.480
sudo ./setup.sh
アンインストールは
/etc/webmin/uninstall.sh

[アプリケーション]
cotEditor ...テキストエディタ
http://www.aynimac.com/p_blog/files/article.php?...

[MacPorts]
http://www.macports.org/
パッケージからインストール
/User/kuwa/.bash_profile というファイルを作って、(これ必要なくなってるかも)
export PATH=/opt/local/bin:/opt/local/sbin/:$PATH
export MANPATH=/opt/local/man:$MANPATH

Terminalの新しいウインドウで、
sudo port -d selfupdate
sudo port -d sync

[不可視ファイルの表示]
defaults write com.apple.finder AppleShowAllFiles true
killall Finder
非表示
defaults write com.apple.finder AppleShowAllFiles false

[MySQL]
port search mysql5
port variants mysql5
で情報を調べてから、
sudo port install -v mysql5-server
■データベースの作成
sudo /opt/local/bin/mysql_install_db5
cd /opt/local/var/db
sudo chown -R mysql:mysql mysql5
cd /opt/local/var
sudo mkdir run
sudo mkdir run/mysql5
sudo chown -R mysql:mysql run
■自動起動
sudo launchctl load -w /Library/LaunchDaemons/org.macports.mysql5.plist

最近のは上記plistが見当たらないので、下記ページを参照に(追記:mysql5-serverをインストールすれば入るみたい)
http://d.hatena.ne.jp/kazu_pon/20090802/p1
cd /opt/local/etc/LaunchDaemons
sudo mkdir org.macports.mysql5
cd org.macports.mysql5
sudo curl -O http://robwilkerson.org/_resources/hotlink/blog/mysql5.wrapper
sudo curl -O http://robwilkerson.org/_resources/hotlink/blog/org.macports.mysql5.plist
sudo chown root:wheel *
sudo chmod 755 mysql5.wrapper
sudo chmod 644 org.macports.mysql5.plist
sudo ln -s /opt/local/etc/LaunchDaemons/org.macports.mysql5/org.macports.mysql5.plist /Library/LaunchDaemons/org.macports.mysql5.plist

■webmin設定
/opt/local/lib/mysql5/bin/mysqlshow
/opt/local/lib/mysql5/bin/mysqladmin
/opt/local/lib/mysql5/bin/mysql
/opt/local/lib/mysql5/bin/mysqldump
/opt/local/lib/mysql5/bin/mysqlimport
cd /opt/local ; /opt/local/lib/mysql5/bin/mysqld_safe &

MySQL共有ライブラリディレクトリへのパス
/opt/local/lib/mysql5/mysql
Path to MySQL databases directory
/opt/local/var/db/mysql5

■rootパスワードの設定 (webminでも設定できる)
sudo /opt/local/lib/mysql5/bin/mysqladmin -u root password 'new-password'

■起動と停止
起動
cd /opt/local ; /opt/local/lib/mysql5/bin/mysqld_safe &
終了
sudo /opt/local/lib/mysql5/bin/mysqladmin -u root -p shutdown
接続
cd /opt/local/lib/mysql5/bin/mysql -u root -p
/opt/local/bin/mysql5 -u root -p
でもいい。

とりあえず、空のmy.cnfを作成(ないと自動起動しない)
sudo touch /etc/my.cnf

[apache2のインストール]
sudo port -d install apache2

■webmin設定
/opt/local/apache2
/opt/local/apache2/bin/httpd
/opt/local/apache2/bin/apachectl
/opt/local/apache2/conf/httpd.conf
/opt/local/apache2/conf/mime.types

■自動起動
sudo launchctl load -w /Library/LaunchDaemons/org.macports.apache2.plist

[php]
xcodeが古いと、xcode 3.1以上が必要とエラーが出るので
AppleのDeveloper Connectionからダウンロードする。
https://connect.apple.com/

port search php5
port variants php5
で調べてから、
sudo port -d install php5-gd +apache2 +mysql5 +pear

■インストールされたモジュールを調べる
/opt/local/bin/php -m
追加インストール
sudo port install php5-mcrypt
sudo port install php5-curl

■php.ini (/opt/local/etc/php5/php.ini)
cd /opt/local/etc/php5; cp php.ini-production php.ini

この辺りを追加・修正
mbstring.internal_encodeing = UTF-8
date.timezone = Asia/Tokyo
upload_max_filesize = 8M

[PEAR]
■XML_RPC
sudo /opt/local/bin/pear install -f XML_RPC
■Text_Diff
sudo /opt/local/bin/pear install -f Text_Diff
■Cache_Lite
sudo /opt/local/bin/pear install -f Cache_Lite
■Net_POP3
sudo /opt/local/bin/pear install Net_POP3-1.3.7
■Mail_Mime (Net_POP3に必要)
sudo /opt/local/bin/pear install Mail_Mime
■Auth_SASL (Net_POP3に必要)
sudo /opt/local/bin/pear install Auth_SASL-1.0.3

[crontab]
webminで設定(初期のまま)
/usr/lib/cron/tabs

1日1回、時間設定 (システム環境設定「日付と時刻」の自動的に設定は、Offにしておく)
/usr/sbin/ntpdate time.asia.apple.com 1>>/var/log/cron.log 2>>/var/log/cron_error.log

[システム環境設定]
ネットワークを手入力に
省エネルギー設定で、スリープしない、停電後に自動再起動
bluetooth関係は切っておく方が無難

[rootパスワードの設定]
ディレクトリユーティリティにて
編集 > ルートユーザーを有効にする

[BIND] ...LANからドメインでアクセスできるように
ここを参照して、webminで設定
http://earlybirds.ddo.jp/namahage/in...

ネームサーバーの起動には、
sudo /usr/sbin/rndc-confgen -a
をやっとく必要有。

■BINDの自動起動
sudo launchctl load -w /System/Library/LaunchDaemons/org.isc.named.plist
終了
sudo launchctl unload -w /System/Library/LaunchDaemons/org.isc.named.plist

プロセスIDを調べる
ps ax | grep named | grep -v grep

自分のマシンのキャッシュクリア
dscacheutil -flushcache

[mecab]
sudo port install mecab @0.96 +utf8only
■ユーザー辞書の追加
http://www.rottel.net/kuwa/34557

[Jcode.pm] (awstats用)
http://openlab.ring.gr.jp/Jcode/index-j.html
ダウンロードして解凍後、
cd Jcode-*
perl Makefile.PL; make
sudo make install
perlのパス
/opt/local/bin/perl

[sleepモードの設定] ... sleepimageファイル容量の節約
sudo pmset -a hibernatemode 0
sudo rm /var/vm/sleepimage
▼追記 2009/10/17 17:10
Macportのphp5のインストールだけでは、mysqlに接続できなくなっている。
分離されたようだ。下記で追加インストール。
sudo port install php5-mysql

さらに、php.iniを修正する必要あり。
mysql.default_socket = /opt/local/var/run/mysql5/mysqld.sock
pdo_mysql.default_socket= /opt/local/var/run/mysql5/mysqld.sock
mysqli.default_socket = /opt/local/var/run/mysql5/mysqld.sock
mysql.default_port = 3306

▼追記 2009/10/20 13:40
mbstringが入ってないじゃないか...
sudo port install php5-mbstring

比較してみると、これまで入っていたもので入らないものがたくさんある。
sudo port install php5-exif
sudo port install php5-curl
sudo port install php5-openssl
sudo port install php5-ftp
sudo port install php5-iconv
sudo port install php5-zip
sudo port install php5-dba
sudo port install php5-calendar
sudo port install php5-gettext
sudo port install php5-posix
sudo port install php5-sorp
sudo port install php5-sqlite

フォーム、$_POSTで受け取ったデータの最初の処理

ブログ | 2009/7/1 12:09
MySQLで処理する準備として、
foreach(array('name','age') as $fk){
 $post[$fk] = isset($_POST[$fk]) ? $_POST[$fk] : '';
 $$fk = m($post[$fk]);
}
これを定番としとくか。(mは、mysql_real_escape_string)

必要なfieldをforeachで回して、
$nameや$ageにエスケープされた文字が入り、
$postにそのままの必要なデータが用意される。

[ポイント]
1, MySQLで扱う時は、変数で持っていた方が楽。
2, エスケープされてないものも持っていた方が、何かと使う。

だいたい、こんな感じで書いちゃって、
$name = isset($_POST['name']) ? m($_POST['name']) : '';
$nameを使い回しちゃってることが多いのだけれど、変えていってみる。

INSERT INTO table (f,f,f) VALUES (値,値,値); は、

ブログ | 2009/4/27 20:50
INSERT INTO table SET f=値,f=値,f=値;
でもいいのだ。

プログラム的に、UPDATEとINSERTを、振り分けることが多いから、こっちの書き方の方が、いろいろ共通化できていいのかもしれない。

MySQL 逆にREGEXP

ブログ | 2009/4/22 15:13
SELECT * FROM table WHERE field REGEXP 'iamaho';
というのは頻繁に使っているのだけれど、
SELECT * FROM table WHERE 'iamahodamonne' REGEXP field;
こういう事もできるようだ。

パワボ

ブログ | 2009/4/20 02:30
きっと、あれやこれややっていたからなのだろうけれど、サーバーが重くなってプロセスが溜まってニッチもサッチもいかなくなったので、パワーボタンで再起動したのです。SSDだから再起動は速い。

で、何事もなくなったと高を括っていたのだけれど、DBが壊れていたようだ。おそらく再起動のタイミングでアクセスされていたテーブルだったのだと思う。スレーブも全部止まってしまった。

で、repair tablesをして、バックアップして、スレーブを作り直して復旧。

アクセスしてたみなさん、ゴメンナサイ。

強制再起動後は気をつけよう。

数ヶ月前の月を取得

ブログ | 2009/4/8 15:38
echo date('Y-m',strtotime('- 7 months'));

ホヘー。
▼追記 2009/5/8 11:15
SQLの場合
date > ADDDATE(CURDATE(),INTERVAL -7 DAY)
か。

InitialSlidersState

ブログ | 2009/2/24 20:25
phpMyAdmin 3.1.2デフォルト設定にて。
構造ページでインデックスやスタッツが「詳細」を押さなければ表示できなくて、とてもやっかいだった。で、ようやくそれらしき設定を発見。

config.inc.php
$cfg['InitialSlidersState'] = 'open';
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

Rottel内コンテンツ

ユーザー一覧

Rottelとは?
利用規約
開発飲料
利用者の声
ヘルプ
close