DynamoDBをちらっと触ってます

なんだかBlogをさぼり続けて早数年w
2012はもう少し書き連ねていきたいものだ。純粋に諸事情もあり、今までの10分の1以下しかないのでしょうがないのかも。ああ20代って時間あってよかったんですねw


DynamoDBを触っている。パフォーマンスもそこそこ測定しているけど、データを見る限り予測できるパフォーマンスだという触れ込みは正しくて、その点は今までのNoSQLよりはやりやすい気がしている。そのうちにどこかで公開したいとは思う。もう少しデータを増やしていきたい。

ProvisionThroughputのところは、それなりに癖をおぼえないといけない気はしてる。というのも、テーブルを一度作ると、そこからのIOPSの向上は最高で100%まで、つまり現状の2倍までしか設定できない。
最初の設計段階で想定のIOPSがどの程度かをきちんと想定して測定したうえで、IOPS値を決めておく必要はありそう。そうでない場合は、ExecutionContextのCustomBackoffStrategyなどを設定して、リトライのところでフックしたりとかして、ごにょごにょして徐々にupdateTableするのが良い気がする(あ、Javaの場合)。ExecutionContextは腹にRequestHandlerをかかえているからそことうまく連携すればクライアントだけでもだいぶDynamoの状況をみたり、その他のAWSサービスとの連携・通知が出来そうですが、まだそういうことをしている人が全然いなそうで、その事実はちょい残念。あと、CustomBackoffStrategyをごにょる際はポリシーみたいなものを導入するんでしょうね。ここらへんは設計モデルがだいぶ変わりそうで色々出来そうです。楽しみ。

モデルをそのままモデルで1対1で落とし込めるという事は、S3かなんかに実際のクラスファイルだけおいておいてダイナミックにロードするとかそんなバカみたいな事をするのもありかもw


さて、現在触る時は

  1. AWS Eclipse Toolkit
  2. AWS Java SDK

で触っているが、その中でもDynamoDBMapperがそれなりに使いやすい気はしてます。アノテーションベースでさらっとモデルを書いて、それを使って基本的なやりとりは出来る。RDBMS+近代的なORMほどいかないけど、結構これで事足りるケースもありそうな気はする。@DynamoDBVersionAttributeでバージョン番号による楽観的ロックも出来る。Atomic counterが内部であるので出来るってことですかねー。あと、Eclipseツールキットも大分使いやすくなっていて、開発者の人は楽そうです。


まあしょぼコードだけども、以下のとおり。あ、事前にデータはいれておいてくださいねっと。
正直モデルはアクセサなしでもいいんじゃと思うけど、Java流儀に従った格好ですかね。


import java.util.Set;

import com.amazonaws.services.dynamodb.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodb.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodb.datamodeling.DynamoDBRangeKey;
import com.amazonaws.services.dynamodb.datamodeling.DynamoDBTable;
import com.amazonaws.services.dynamodb.datamodeling.DynamoDBVersionAttribute;

@DynamoDBTable(tableName = "Thread")
public class ForumThread {

	String forumName;

	String subject;

	String message;

	String lastPostedBy;

	String lastPostedDateTime;

	Long views;

	Long replies;

	Long answered;

	Long version;
	
	Set<String> tags;

	@DynamoDBHashKey(attributeName = "ForumName")
	public String getForumName() {
		return forumName;
	}

	public void setForumName(String forumName) {
		this.forumName = forumName;
	}

	@DynamoDBRangeKey(attributeName = "Subject")
	public String getSubject() {
		return subject;
	}

	public void setSubject(String subject) {
		this.subject = subject;
	}

	@DynamoDBAttribute(attributeName = "Message")
	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	@DynamoDBAttribute(attributeName = "LastPostedBy")
	public String getLastPostedBy() {
		return lastPostedBy;
	}

	public void setLastPostedBy(String lastPostedBy) {
		this.lastPostedBy = lastPostedBy;
	}

	@DynamoDBAttribute(attributeName = "LastPostedDateTime")
	public String getLastPostedDateTime() {
		return lastPostedDateTime;
	}

	public void setLastPostedDateTime(String lastPostedDateTime) {
		this.lastPostedDateTime = lastPostedDateTime;
	}

	@DynamoDBAttribute(attributeName = "Views")
	public Long getViews() {
		return views;
	}

	public void setViews(Long views) {
		this.views = views;
	}

	@DynamoDBAttribute(attributeName = "Replies")
	public Long getReplies() {
		return replies;
	}

	public void setReplies(Long replies) {
		this.replies = replies;
	}

	@DynamoDBAttribute(attributeName = "Answered")
	public Long getAnswered() {
		return answered;
	}

	public void setAnswered(Long answered) {
		this.answered = answered;
	}

	@DynamoDBAttribute(attributeName = "Tags")
	public Set<String> getTags() {
		return tags;
	}

	public void setTags(Set<String> tags) {
		this.tags = tags;
	}

	@DynamoDBVersionAttribute(attributeName = "Version")
	public Long getVersion() {
		return version;
	}

	public void setVersion(Long version) {
		this.version = version;
	}
	
}
import java.util.Arrays;
import java.util.List;

import com.amazonaws.services.dynamodb.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodb.datamodeling.DynamoDBQueryExpression;
import com.amazonaws.services.dynamodb.model.AttributeValue;
import com.amazonaws.services.dynamodb.model.ComparisonOperator;
import com.amazonaws.services.dynamodb.model.Condition;

public class MapperMainForHashAndRange {

	public static void main(String[] args) {
		DynamoDBMapper mapper = new DynamoDBMapper(Util.createClient());
		ForumThread ret = mapper.load(ForumThread.class, "Amazon DynamoDB",
				"DynamoDB Thread 1");
		System.out.println("1st:" + ret + "(" + ret.getVersion() + ")");

		ret.setMessage("DynamoDB thread 1 message:"
				+ System.currentTimeMillis());
		mapper.save(ret);

		ret = mapper.load(ForumThread.class, "Amazon DynamoDB",
				"DynamoDB Thread 1");
		System.out.println("2nd:" + ret + "(" + ret.getVersion() + ")");

		DynamoDBQueryExpression exp = new DynamoDBQueryExpression(
				new AttributeValue().withS("Amazon DynamoDB"));
		{
			Condition rangeKeyCondition = new Condition();
			rangeKeyCondition.setAttributeValueList(Arrays
					.asList(new AttributeValue("DynamoDB Thread 1")));
			rangeKeyCondition.setComparisonOperator(ComparisonOperator.NE);
			exp.setRangeKeyCondition(rangeKeyCondition);
		}
		try {
			List<ForumThread> result = mapper.query(ForumThread.class, exp);
			if (result != null) {
				for (ForumThread c : result) {
					System.out.println("return from query:" + c);
				}
			}
		} catch (Exception e) {
			//logging and throw error...
		}
	}
}


現状やっている範囲がプリミティブなことしかしていないので、それであれば低レベルAPIも高レベルAPIもあまりパフォーマンスに影響がでていない。大がかりにやれば変わってくるだろうけども、ささっと始める分には非常によいんじゃないかと思うです。