■ 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での日本語の検索を試してみたいと思います。
技術評論社
売り上げランキング: 5,985
コメント