Amazon CloudSearchのクライアントプログラミング

■ Search Data Format (SDF)
 
Amazon CloudSearchでデータをインデクシングするのにSDFというフォーマット(JSONもしくはXML)で
データをアップロードする必要がありますが、2014年1月現在、以下の方法があります。
1. コマンドラインツールをインストールしてcs-import-documentsコマンドを使う
2. ManagementConsoleでブラウザからポチポチする
3. DocumentEndpointに直接curl等でPOSTする
 
SDFフォーマット的には↓に詳しく記載されていますが、
http://aws.amazon.com/articles/8871401284621700#_Ref198105621
 
以下のような情報が必要な感じになります。
– 操作種別(add/delete)
– 一意の識別子
– バージョン番号
– 言語コード(en)
– 実際のフィールドとデータ
 
 
■ SDKを使って開発しているのでその中でやりくりしたい
 
先日、Solrをイジっていて、SolrJでクライアントプログラミングしてみました(http://shinodogg.com/?p=5899)が、
ソレと同じようなノリで、Javaのオブジェクトを作って、そのままインデクシングしたいな、と。
 
 
■ まずはAmazon CloudSearchに検索サーバーを準備してSDKからアクセス
 
CloudSearchにDomainを定義します。
(後からtextフィールドもresultのチェック入れましたが、件数なくてもActiveになるまでそこそこ時間かかります)

 
JavaのSDKのCloudSearchなクラスを使ってアクセスしてみます。
 
– CloudSearchのクライアント。リージョンはVirginia(まだ日本にきてないので)

AmazonCloudSearchClient client = new AmazonCloudSearchClient(new PropertiesCredentials(SampleIndexer.class.getResourceAsStream("AwsCredentials.properties")));
client.setRegion(Region.getRegion(Regions.US_EAST_1));

 
– 検索ドメインを表示
↓この辺の情報が取れます。(複数ドメインがあれば複数)
・ドメインのID, 名前, 作成済み, 削除済み, 検索対象ドキュメント数
・ドキュメントサービス(インデクシング)のエンドポイント, サーチサービスのエンドポイント
・インスタンスのタイプや数、パーティション数なんかも

DescribeDomainsResult describeDomainsResult = client.describeDomains();
List domainStatusList = describeDomainsResult.getDomainStatusList();
for (DomainStatus status: domainStatusList) {
    System.out.println(status);
}

 
– ドメインのフィールドを表示

DescribeIndexFieldsRequest describeIndexFieldsRequest = new DescribeIndexFieldsRequest();
describeIndexFieldsRequest.withDomainName("sample");
DescribeIndexFieldsResult indexFieldsResult = client.describeIndexFields(describeIndexFieldsRequest);
List indexFieldStatusList = indexFieldsResult.getIndexFields();
for (IndexFieldStatus idxFieldStatus : indexFieldStatusList) {
    System.out.println(idxFieldStatus);
}

↓こんな感じでイロイロ取れます。いつそのフィールドのドメイン定義がUpdateされた〜とか。

{Options: {IndexFieldName: detail,IndexFieldType: text,TextOptions: {FacetEnabled: false,ResultEnabled: true,},SourceAttributes: []},Status: {CreationDate: Tue Jan 07 16:01:26 JST 2014,UpdateDate: Tue Jan 07 20:43:00 JST 2014,UpdateVersion: 22,State: Active,PendingDeletion: false}}
{Options: {IndexFieldName: head,IndexFieldType: text,TextOptions: {FacetEnabled: false,ResultEnabled: true,},SourceAttributes: []},Status: {CreationDate: Tue Jan 07 16:01:25 JST 2014,UpdateDate: Tue Jan 07 20:43:00 JST 2014,UpdateVersion: 22,State: Active,PendingDeletion: false}}
{Options: {IndexFieldName: id,IndexFieldType: uint,SourceAttributes: []},Status: {CreationDate: Tue Jan 07 16:01:23 JST 2014,UpdateDate: Tue Jan 07 16:31:16 JST 2014,UpdateVersion: 14,State: Active,PendingDeletion: false}}

 
んま、とりあえず、SDKを使ってCloudSearchと会話できる確認がとれましたよ、と。
 
 
■ JavaのオブジェクトからSDFを生成してPOSTする
 
SDFと言っても、普通のJSON(もしくはXML)なので、普通にバリューオブジェクトを作れば良さそうです。
 
ということで、まずはJavaなJSON用ライブラリ。
以前はよくJacksonというライブラリを使っていましたが、ググったらGoogleのがあるらしいので
(その名もGson。ストレートな名前がグッときますね。笑)、それを使ってみます。
↓pom.xmlに定義を追加してmavenでjarファイルをダウンロードしてきます。

<dependencies>
    <!--  Gson: Java to Json conversion -->
    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.2.4</version>
      <scope>compile</scope>
    </dependency>
</dependencies>

 
– Valueオブジェクトを作ります。
・SDF

public class SDF {
	private String type; //操作種別(add/delete)
	private String id; //一意の識別子
	private int version; //バージョン番号
	private String lang; //言語コード(en)
	private Sample fields; //実際のフィールドとデータ
〜 setterとgetterは省略 〜

・ドメインで定義したヤツ

public class Sample {
	private int id;
	private String head;
	private String detail;
〜 setterとgetterは省略 〜

 
– ドカっと値を詰めてやります。

List<SDF> sdfList = new ArrayList<SDF>();

SDF sdf = new SDF();
sdf.setType("add");
sdf.setId("111111");
sdf.setVersion(1111);
sdf.setLang("en");
Sample sample = new Sample();
sample.setId(1111);
sample.setHead("sample head 11");
sample.setDetail("sample detail 12");
sdf.setFields(sample);
sdfList.add(sdf);

sdf = new SDF();
sdf.setType("add");
sdf.setId("111112");
sdf.setVersion(1111);
sdf.setLang("en");
sample = new Sample();
sample.setId(1112);
sample.setHead("head bungin");
sample.setDetail("detail junkie");
sdf.setFields(sample);
sdfList.add(sdf);

 
上記で2レコードを追加するJavaなオブジェクトが出来上がりました。
 
– オブジェクトをJSON文字列に。スッゲー簡単…。

Gson gson = new Gson();
System.out.println(gson.toJson(sdfList));

↓インデントするとこんな感じになります。

[
    {
        "fields": {
            "detail": "sample detail 12",
            "head": "sample head 11",
            "id": 1111
        },
        "id": "111111",
        "lang": "en",
        "type": "add",
        "version": 1111
    },
    {
        "fields": {
            "detail": "detail junkie",
            "head": "head bungin",
            "id": 1112
        },
        "id": "111112",
        "lang": "en",
        "type": "add",
        "version": 1111
    }
]

 
– よくあるHTTPクライアントなヤツ

HttpClient httpClient = new DefaultHttpClient();

// POSTでドキュメントエンドポイントに。
// URLの最後の方の"2011-02-01"はCloudSearchのバージョン名で今のところコレです。
HttpPost post = new HttpPost("http://doc-sample-xxx.us-east-1.cloudsearch.amazonaws.com/2011-02-01/documents/batch");

// JavaオブジェクトをJSONにしてContentTypeの設定&エンティティにセット
StringEntity entity = new StringEntity(gson.toJson(sdfList));
entity.setContentType("application/json");
post.setEntity(entity);

// 実行して結果を取得
HttpResponse response = httpClient.execute(post);
System.out.println(response.getStatusLine());
String responseString = EntityUtils.toString(response.getEntity());
System.out.println(responseString);

 
– 実行結果
ステータスコードと何件追加したよ的なヤツが返ってきます。

HTTP/1.1 200 OK
{"status": "success", "adds": 2, "deletes": 0}

 
 
■ ManagementConsoleからクエリ
 
↓正しくインデックスされていることが確認出来ました。

 
上記のコードも大量にデータを扱うとなるとイロイロとチューニングなポイントがありそうですが、
一般的なライブラリの組み合わせでやりくり出来そうです。
 
 
■ 次回は、、
 
SnapDishの清田さんのブログで形態素解析まわりをCloudSearchの外でやって、
日本語でもCloudSearchを活用されている例が紹介されていますが、
Yahoo!さんが日本語形態素解析APIを公開していたりするので、
そちらを使ってCloudSearchでの日本語の検索を試してみたいと思います。
 
 

[改訂新版] Apache Solr入門 ~オープンソース全文検索エンジン (Software Design plus)
大谷 純 阿部 慎一朗 大須賀 稔 北野 太郎 鈴木 教嗣 平賀 一昭
技術評論社
売り上げランキング: 5,985

コメント

タイトルとURLをコピーしました