当社Webサイト

カテゴリー

Amazonサーチ

  • 07/15
    Java, Solr, プログラム, 全文検索 post by kubo@eni.co.jp @ 2009 年 7 月 15 日 15:38

    こんにちは。
    株式会社イージーネット プロダクト&サービス事業部 の久保です。

    前回書いたSolrの記事 全文検索サーバ: これからSolrを始める人のためのApache Solr概要と便利なリンク集 はおかげさまで沢山のアクセス/ブックマークをいただきました。
    来週火曜日の7/21には、Lucene/Solrで有名なロンウイットの関口さん(参考: 関口宏司のLuceneブログ)などが参加されるSolr勉強会も開催されるようですので、Solr人気は高まっているのかもしれません。

    今回は前回から変わって小さなネタになりますが、
    Solr/SolrJ1.3のCoreAdmin(マルチコア)機能を用いて動的にCoreを追加する際にはまるSolrJのバグと、その対処方法について書きます。

    Solr1.3のマルチコア機能とは

    単純に言うと、1つのSolrアプリケーション(サーブレットアプリケーション)の上で、論理的に複数のSolrアプリケーションを動かすことができる機能です。
    詳しくは前回の記事の「マルチコア構成」をご覧ください。

    Coreを追加するためのURL(Query String)

    Coreを追加するのに必要なURL(Query String)は次のようになります。
    (参考URL: Solr Wiki – CoreAdmin)

    http://server/solr/admin/cores?action=CREATE&name=[name]&instanceDir=[dir]&config=[solrconfig]&schema=[schema]

    (例)

    http://testserver:8080/solr/admin/cores?action=CREATE&name=test&instanceDir=test&config=/solr/conf/solrconfig.xml&schema=/solr/conf/schema.xml
    [name] coreに付ける名前(例: test)
    [dir] coreのディレクトリ名(例: test)
    [solrconfig] solrconfig.xmlファイルのパス(例: /solr/conf/solrconfig.xml)
    [schema] schema.xmlファイル(例: /solr/conf/schema.xml)

    SolrJを使った場合の問題

    SolrJのver1.3において、SolrCoreAdminRequestのcreateCoreメソッドを使った以下のコードは失敗します。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    
    package jp.co.eni.solr.test;
     
    import java.io.IOException;
    import java.net.MalformedURLException;
     
    import org.apache.solr.client.solrj.SolrServer;
    import org.apache.solr.client.solrj.SolrServerException;
    import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
    import org.apache.solr.client.solrj.request.CoreAdminRequest;
    import org.apache.solr.client.solrj.response.CoreAdminResponse;
     
    //失敗する
    public class FailedCoreCreateTest {
    	public static void main(String[] args) {
    		try {
    			// SolrのURL
    			String url = "http://server/solr/";
    			// coreの名前
    			String coreName = "failed";
    			// coreのディレクトリ名
    			String instanceDir = "failed";
     
    			SolrServer server = new CommonsHttpSolrServer(url);
    			CoreAdminResponse response = CoreAdminRequest.createCore(coreName, instanceDir, server);
    			System.out.println("qtime: " + response.getQTime());
    		} catch (MalformedURLException e) {
    			e.printStackTrace();
    		} catch (SolrServerException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }

    失敗の原因は、上記コードにより生成されるHTTP RequestのQuery Stringにあります。
    エラーのログを見ると、

    Exception in thread "main" org.apache.solr.common.SolrException: Internal Server Error
     
    Internal Server Error
     
    request: http://server/solr/admin/cores?action=CREATE&core=failed&instanceDir=failed&wt=javabin&version=2.2
    	at org.apache.solr.client.solrj.impl.CommonsHttpSolrServer.request(CommonsHttpSolrServer.java:343)
    	at org.apache.solr.client.solrj.impl.CommonsHttpSolrServer.request(CommonsHttpSolrServer.java:183)
    	at org.apache.solr.client.solrj.request.CoreAdminRequest.process(CoreAdminRequest.java:170)
    	at org.apache.solr.client.solrj.request.CoreAdminRequest.createCore(CoreAdminRequest.java:226)
    	at jp.co.eni.solr.test.FailedCoreCreateTest.main(FailedCoreCreateTest.java:23)

    とあるように、

    name=failed

    ではなく

    core=failed

    となっていることが分かります。
    これは、SolrJ1.3のorg.apache.solr.client.solrj.request.CoreAdminRequest.Create#getParames(rev:688188)が以下のような実装になっているためです。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
        @Override
        public SolrParams getParams() {
          if( action == null ) {
            throw new RuntimeException( "no action specified!" );
          }
          ModifiableSolrParams params = new ModifiableSolrParams();
          params.set( CoreAdminParams.ACTION, action.toString() );
          params.set( CoreAdminParams.CORE, core );                      //←※ここがおかしい
          params.set( CoreAdminParams.INSTANCE_DIR, instanceDir);
          if (configName != null) {
            params.set( CoreAdminParams.CONFIG, configName);
          }
          if (schemaName != null) {
            params.set( CoreAdminParams.SCHEMA, schemaName);
          }
          return params;
        }

    簡単な解決策

    以下のようなCoreAdminRequest.Createの拡張クラスを用意することで、上記の問題を解決することができます。

    用意するクラス

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    
    package jp.co.eni.solr.test;
     
    import org.apache.solr.client.solrj.request.CoreAdminRequest.Create;
    import org.apache.solr.common.params.CoreAdminParams;
    import org.apache.solr.common.params.ModifiableSolrParams;
    import org.apache.solr.common.params.SolrParams;
     
    public class SolvedCreate extends Create {
    	/**
    	 * コンストラクタ
    	 *
    	 * @param coreName
    	 * @param instanceDir
    	 * @param configName
    	 * @param schemaName
    	 */
    	public SolvedCreate(String coreName, String instanceDir, String configName, String schemaName) {
    		super();
    		// coreの名前
    		setCoreName(coreName);
    		// coreのディレクトリ名
    		setInstanceDir(instanceDir);
    		// solrconfig.xmlのパス
    		setConfigName(configName);
    		// schema.xmlのパス
    		setSchemaName(schemaName);
    	}
     
    	@Override
    	public SolrParams getParams() {
    		ModifiableSolrParams params = (ModifiableSolrParams) super.getParams();
    		// coreではなくnameを使う
    		params.set(CoreAdminParams.CORE, (String) null);
    		params.set(CoreAdminParams.NAME, core);
     
    		return params;
    	}
    }

    getParamsメソッドは、org.apache.solr.client.solrj.impl.CommonsHttpSolrServer#requestの中で呼ばれます。

    CoreAdminParams.COREやCoreAdminParams.NAMEを持つorg.apache.solr.common.params.CoreAdminParamsというのは以下のようなインタフェースになっており、
    COREではなくNAMEを用いるのが正しそうだということになります。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    public interface CoreAdminParams 
    {
      /** What Core are we talking about **/
      public final static String CORE = "core";
     
      /** Persistent -- should it save the cores state? **/
      public final static String PERSISTENT = "persistent";
     
      /** If you rename something, what is the new name **/
      public final static String NAME = "name";
     
      // 後略

    SolvedCreate利用コード

    上記のSolvedCreateクラスを利用したコードは次のようになります。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    
    package jp.co.eni.solr.test;
     
    import java.io.IOException;
    import java.net.MalformedURLException;
     
    import org.apache.solr.client.solrj.SolrServer;
    import org.apache.solr.client.solrj.SolrServerException;
    import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
    import org.apache.solr.client.solrj.response.CoreAdminResponse;
     
    // 成功する
    public class SuccessCoreCreateTest {
    	public static void main(String[] args) {
    		try {
    			// SolrのURL
    			String url = "http://server/solr/";
    			// coreの名前
    			String coreName = "name2";
    			// coreのディレクトリ名
    			String instanceDir = "dir2";
    			// solrconfig.xmlのパス
    			String configName = "/solr/conf/solrconfig.xml";
    			// schema.xmlのパス
    			String schemaName = "/solr/conf/schema.xml";
     
    			// Createクラスのバグ対応のため、SolvedCreateクラスを作成して使っている
    			SolvedCreate createRequest = new SolvedCreate(coreName, instanceDir, configName, schemaName);
    			SolrServer server = new CommonsHttpSolrServer(url);
    			CoreAdminResponse response = createRequest.process(server);
    			System.out.println("qtime: " + response.getQTime());
    		} catch (MalformedURLException e) {
    			e.printStackTrace();
    		} catch (SolrServerException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }

    1.4では修正される模様

    この問題は、Apacheプロジェクトのバグトラックにも登録されています。
    SOLR-803: CoreAdminRequest.createCore fails because name parameter isn’t setを見ると、StatusはResolveとなっています。
    Solrのレポジトリを直接確認してみたところ、上記の問題はrev.708266の修正で解決されているようです。

    SOLR-803: fix CoreAdminRequest.createCore error

    コードは確認していませんが、ちゃんとした?修正がされていそうです。

    またpache Solr Version 1.4-dev Release Notesを見ると、SOLR-803も含まれていますので、1.4のリリース時にはこのエントリで取り上げた問題は発生しなくなるはずです。

    参考URL

    使用したソフトウェア

    ソフトウェア バージョン
    Solr 1.3
    SolrJ 1.3

    あわせて読みたい

    Tags: , , , , ,

One Response

WP_Cloudy