Sphinx:デルタインデックスと複数の検索サーバー

多かれ少なかれ大規模なプロジェクトでは、遅かれ早かれ、全文コンテンツ検索が必要になります。

この目的のために、 Sphinx検索エンジンが発明されました。



ベースが大きくなるか、インデックスが大量になると、インデックスの再作成に非常に長い時間がかかり始めます。これは、プロジェクトにさまざまな悪影響を与える可能性があります。 この時点で、 デルタインデックスの使用を検討する必要があります

著者は、インデックスの再作成に1時間以上かかり始めたときに、このニーズに直面しました。



しかし、これらはすべてドキュメントで詳細に説明されており、非常に簡単に実行されます。

source src_mysql { type = mysql sql_host = localhost sql_user = sphinx sql_pass = secret sql_range_step = 1000 } source src_news : src_mysql { sql_db = project sql_query_pre = SET NAMES utf8 sql_query_pre = SET CHARACTER SET utf8 sql_query_pre = REPLACE INTO sph_counter SELECT 'src_news', MAX(id) FROM news sql_query_range = SELECT MIN(id), MAX(id) FROM news sql_query = SELECT id as news_id, title, content FROM news WHERE id>=$start AND id<=$end } source src_news_delta : src_news { sql_query_pre = SET NAMES utf8 sql_query_pre = SET CHARACTER SET utf8 sql_query_range = sql_query = SELECT id as news_id title, content FROM news \ WHERE id > ( SELECT max_value FROM sph_counter WHERE source = 'src_news') sql_query_post = REPLACE INTO sph_counter SELECT 'src_news', MAX(id) FROM news }
      
      







次に、複数のインデックスサーバーがある場合を考えます。 これにはいくつかの理由が考えられますが、問題が発生します。インデックスを作成した後、1つのサーバーがデータベースの最後のIDの値を上書きします。 次のサーバーでインデックス作成が開始されると、前のサーバーによってインデックスが作成されたレコードは選択に含まれません。 インデックスには「ギャップ」があり、検索結果は常に異なり、ランダムな結果は失われます。



どうする



sph_counterテーブルにインデックスサーバーIDを追加で保存する必要があります。



ホスト名列を追加します。



その結果、テーブルは次のようになります。

 CREATE TABLE IF NOT EXISTS `sph_counter` ( `source` varchar(100) NOT NULL DEFAULT '', `max_value` bigint(20) NOT NULL, `hostname` varchar(50) NOT NULL DEFAULT '', PRIMARY KEY (`source`,`hostname`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
      
      





* インデックスに注意してください。REPLACEINTOを正しく動作させるために必要です。



次に、オプション2の構成に応じて:



1. Sphinxプロセスはデータベースと同じサーバーで実行され、マスターマスターレプリケーションが構成されます


この状況では、問題は非常に簡単に解決されます。グローバルMySQL変数-'hostname'を使用します

設定は次の形式を取ります。

 source src_news : src_mysql { sql_db = project sql_query_pre = SET NAMES utf8 sql_query_pre = SET CHARACTER SET utf8 sql_query_pre = REPLACE INTO sph_counter SELECT 'src_news', MAX(id), @@hostname FROM news sql_query_range = SELECT MIN(id), MAX(id) FROM news sql_query = SELECT id as news_id, title, content FROM news WHERE id>=$start AND id<=$end } source src_news_delta : src_news { sql_query_pre = SET NAMES utf8 sql_query_pre = SET CHARACTER SET utf8 sql_query_range = sql_query = SELECT id as news_id, title, content FROM news \ WHERE id > ( SELECT max_value FROM sph_counter WHERE source = 'src_news' AND hostname = @@hostname) sql_query_post = REPLACE INTO sph_counter SELECT 'src_news', MAX(id), @@hostname FROM news }
      
      







2. MySQLとSphinxサーバーは異なり、リクエストはマスターに送られます


この場合、 ホスト名グローバル変数は使用できなくなります。データベースが実行されているサーバーの名前を常に取得します。



終了:接続情報とユーザー変数を使用します。



 source src_news : src_mysql { sql_db = project sql_query_pre = SET NAMES utf8 sql_query_pre = SET CHARACTER SET utf8 sql_query_pre = SELECT @sphinx_instance:=IF(STRCMP(@sphinx_host:=SUBSTRING_INDEX(host,':',1),'localhost'),@sphinx_host,@@hostname) AS sphinx_instance \ FROM information_schema.processlist WHERE ID=connection_id(); sql_query_pre = REPLACE INTO sph_counter SELECT 'src_news', MAX(id), @sphinx_instance FROM news sql_query_range = SELECT MIN(id), MAX(id) FROM news sql_query = SELECT id as news_id, title, content FROM news WHERE id>=$start AND id<=$end } source src_news_delta : src_news { sql_query_pre = SET NAMES utf8 sql_query_pre = SET CHARACTER SET utf8 sql_query_pre = SELECT @sphinx_instance:=IF(STRCMP(@sphinx_host:=SUBSTRING_INDEX(host,':',1),'localhost'),@sphinx_host,@@hostname) AS sphinx_instance \ FROM information_schema.processlist WHERE ID=connection_id(); sql_query_pre = REPLACE INTO sph_counter SELECT 'src_news', MAX(id), @sphinx_instance FROM news sql_query_range = sql_query = SELECT id as news_id, title, content FROM news \ WHERE id > ( SELECT max_value FROM sph_counter WHERE source = 'src_news' AND hostname = @sphinx_instance) sql_query_post = REPLACE INTO sph_counter SELECT 'src_news', MAX(id), @sphinx_instance FROM news }
      
      







この構成は、どちらの場合でも機能します。



All Articles