Symfoware

Symfowareについての考察blog

Voldemortのデータにオブジェクトを登録する方法(thrift使用)

Java標準のシリアライズ機能を使用してオブジェクトを変換。
Voldemortのデータとして登録することに成功しました。
Voldemortのデータにオブジェクトを登録する方法(java-serialization使用)


ドキュメントを見てみると、以下のデータ型が使用可能のようです。

json,
java-serialization
string
protobuff
thrift
identity (meaning raw bytes)




stringとjava-serializationは試しましたので、
Debianで動作しているVoldemortをWindows + Javaで操作する
Voldemortのデータにオブジェクトを登録する方法(java-serialization使用)
thriftを使用してみます。





Thriftのインストール



Thriftとは、データ型や関数を定義したファイルをテンプレートとし、
各種言語に適したソースコードに変換してくれるツールです。

以前、Debianにインストールしたときの記事はこちら。
DebianにApache Thriftをインストールする


なお、Thriftは雛形からjavaのソースに変換するだけなので、
Voldemortが動作しているサーバーにインストールする必要はありません。





Thriftの定義体とjavaソースの生成



サンプルとして、こんな定義体を考えました。

■voldemort.thrift


namespace java com.fc2.blog68.symfoware.voldemort

struct ThriftData {
    1:string title,
    2:string details,
    3:list<string> list_sample,
}




titleとdetailsの2つの文字列型とlist_sampleという文字列のリスト型を
保持するThriftDataという構造体を定義します。


javaのソースを得るには、以下のコマンドを実行します。


# thrift --gen java voldemort.thrift




すると、gen-javaというディレクトリが生成されます。
こんな感じで、ソースが出来ます。

gen-java/com/fc2/blog68/symfoware/voldemort/ThriftData.java






Thriftにより生成されたソースです。

■ThriftData.java


/**
* Autogenerated by Thrift
*
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
*/
package com.fc2.blog68.symfoware.voldemort;

import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.EnumMap;
import java.util.Set;
import java.util.HashSet;
import java.util.EnumSet;
import java.util.Collections;
import java.util.BitSet;
import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.apache.thrift.*;
import org.apache.thrift.meta_data.*;
import org.apache.thrift.protocol.*;

public class ThriftData implements TBase<ThriftData._Fields>, java.io.Serializable, Cloneable, Comparable<ThriftData> {
  private static final TStruct STRUCT_DESC = new TStruct("ThriftData");

  private static final TField TITLE_FIELD_DESC = new TField("title", TType.STRING, (short)1);
  private static final TField DETAILS_FIELD_DESC = new TField("details", TType.STRING, (short)2);
  private static final TField LIST_SAMPLE_FIELD_DESC = new TField("list_sample", TType.LIST, (short)3);

  public String title;
  public String details;
  public List<String> list_sample;

  /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
  public enum _Fields implements TFieldIdEnum {
    TITLE((short)1, "title"),
    DETAILS((short)2, "details"),
    LIST_SAMPLE((short)3, "list_sample");

    private static final Map<Integer, _Fields> byId = new HashMap<Integer, _Fields>();
    private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();

    static {
      for (_Fields field : EnumSet.allOf(_Fields.class)) {
        byId.put((int)field._thriftId, field);
        byName.put(field.getFieldName(), field);
      }
    }

    /**
     * Find the _Fields constant that matches fieldId, or null if its not found.
     */
    public static _Fields findByThriftId(int fieldId) {
      return byId.get(fieldId);
    }

    /**
     * Find the _Fields constant that matches fieldId, throwing an exception
     * if it is not found.
     */
    public static _Fields findByThriftIdOrThrow(int fieldId) {
      _Fields fields = findByThriftId(fieldId);
      if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!");
      return fields;
    }

    /**
     * Find the _Fields constant that matches name, or null if its not found.
     */
    public static _Fields findByName(String name) {
      return byName.get(name);
    }

    private final short _thriftId;
    private final String _fieldName;

    _Fields(short thriftId, String fieldName) {
      _thriftId = thriftId;
      _fieldName = fieldName;
    }

    public short getThriftFieldId() {
      return _thriftId;
    }

    public String getFieldName() {
      return _fieldName;
    }
  }

  // isset id assignments

  public static final Map<_Fields, FieldMetaData> metaDataMap = Collections.unmodifiableMap(new EnumMap<_Fields, FieldMetaData>(_Fields.class) {{
    put(_Fields.TITLE, new FieldMetaData("title", TFieldRequirementType.DEFAULT,
        new FieldValueMetaData(TType.STRING)));
    put(_Fields.DETAILS, new FieldMetaData("details", TFieldRequirementType.DEFAULT,
        new FieldValueMetaData(TType.STRING)));
    put(_Fields.LIST_SAMPLE, new FieldMetaData("list_sample", TFieldRequirementType.DEFAULT,
        new ListMetaData(TType.LIST,
            new FieldValueMetaData(TType.STRING))));
  }});

  static {
    FieldMetaData.addStructMetaDataMap(ThriftData.class, metaDataMap);
  }

  public ThriftData() {
  }

  public ThriftData(
    String title,
    String details,
    List<String> list_sample)
  {
    this();
    this.title = title;
    this.details = details;
    this.list_sample = list_sample;
  }

  /**
   * Performs a deep copy on <i>other</i>.
   */
  public ThriftData(ThriftData other) {
    if (other.isSetTitle()) {
      this.title = other.title;
    }
    if (other.isSetDetails()) {
      this.details = other.details;
    }
    if (other.isSetList_sample()) {
      List<String> __this__list_sample = new ArrayList<String>();
      for (String other_element : other.list_sample) {
        __this__list_sample.add(other_element);
      }
      this.list_sample = __this__list_sample;
    }
  }

  public ThriftData deepCopy() {
    return new ThriftData(this);
  }

  @Deprecated
  public ThriftData clone() {
    return new ThriftData(this);
  }

  public String getTitle() {
    return this.title;
  }

  public ThriftData setTitle(String title) {
    this.title = title;
    return this;
  }

  public void unsetTitle() {
    this.title = null;
  }

  /** Returns true if field title is set (has been asigned a value) and false otherwise */
  public boolean isSetTitle() {
    return this.title != null;
  }

  public void setTitleIsSet(boolean value) {
    if (!value) {
      this.title = null;
    }
  }

  public String getDetails() {
    return this.details;
  }

  public ThriftData setDetails(String details) {
    this.details = details;
    return this;
  }

  public void unsetDetails() {
    this.details = null;
  }

  /** Returns true if field details is set (has been asigned a value) and false otherwise */
  public boolean isSetDetails() {
    return this.details != null;
  }

  public void setDetailsIsSet(boolean value) {
    if (!value) {
      this.details = null;
    }
  }

  public int getList_sampleSize() {
    return (this.list_sample == null) ? 0 : this.list_sample.size();
  }

  public java.util.Iterator<String> getList_sampleIterator() {
    return (this.list_sample == null) ? null : this.list_sample.iterator();
  }

  public void addToList_sample(String elem) {
    if (this.list_sample == null) {
      this.list_sample = new ArrayList<String>();
    }
    this.list_sample.add(elem);
  }

  public List<String> getList_sample() {
    return this.list_sample;
  }

  public ThriftData setList_sample(List<String> list_sample) {
    this.list_sample = list_sample;
    return this;
  }

  public void unsetList_sample() {
    this.list_sample = null;
  }

  /** Returns true if field list_sample is set (has been asigned a value) and false otherwise */
  public boolean isSetList_sample() {
    return this.list_sample != null;
  }

  public void setList_sampleIsSet(boolean value) {
    if (!value) {
      this.list_sample = null;
    }
  }

  public void setFieldValue(_Fields field, Object value) {
    switch (field) {
    case TITLE:
      if (value == null) {
        unsetTitle();
      } else {
        setTitle((String)value);
      }
      break;

    case DETAILS:
      if (value == null) {
        unsetDetails();
      } else {
        setDetails((String)value);
      }
      break;

    case LIST_SAMPLE:
      if (value == null) {
        unsetList_sample();
      } else {
        setList_sample((List<String>)value);
      }
      break;

    }
  }

  public void setFieldValue(int fieldID, Object value) {
    setFieldValue(_Fields.findByThriftIdOrThrow(fieldID), value);
  }

  public Object getFieldValue(_Fields field) {
    switch (field) {
    case TITLE:
      return getTitle();

    case DETAILS:
      return getDetails();

    case LIST_SAMPLE:
      return getList_sample();

    }
    throw new IllegalStateException();
  }

  public Object getFieldValue(int fieldId) {
    return getFieldValue(_Fields.findByThriftIdOrThrow(fieldId));
  }

  /** Returns true if field corresponding to fieldID is set (has been asigned a value) and false otherwise */
  public boolean isSet(_Fields field) {
    switch (field) {
    case TITLE:
      return isSetTitle();
    case DETAILS:
      return isSetDetails();
    case LIST_SAMPLE:
      return isSetList_sample();
    }
    throw new IllegalStateException();
  }

  public boolean isSet(int fieldID) {
    return isSet(_Fields.findByThriftIdOrThrow(fieldID));
  }

  @Override
  public boolean equals(Object that) {
    if (that == null)
      return false;
    if (that instanceof ThriftData)
      return this.equals((ThriftData)that);
    return false;
  }

  public boolean equals(ThriftData that) {
    if (that == null)
      return false;

    boolean this_present_title = true && this.isSetTitle();
    boolean that_present_title = true && that.isSetTitle();
    if (this_present_title || that_present_title) {
      if (!(this_present_title && that_present_title))
        return false;
      if (!this.title.equals(that.title))
        return false;
    }

    boolean this_present_details = true && this.isSetDetails();
    boolean that_present_details = true && that.isSetDetails();
    if (this_present_details || that_present_details) {
      if (!(this_present_details && that_present_details))
        return false;
      if (!this.details.equals(that.details))
        return false;
    }

    boolean this_present_list_sample = true && this.isSetList_sample();
    boolean that_present_list_sample = true && that.isSetList_sample();
    if (this_present_list_sample || that_present_list_sample) {
      if (!(this_present_list_sample && that_present_list_sample))
        return false;
      if (!this.list_sample.equals(that.list_sample))
        return false;
    }

    return true;
  }

  @Override
  public int hashCode() {
    return 0;
  }

  public int compareTo(ThriftData other) {
    if (!getClass().equals(other.getClass())) {
      return getClass().getName().compareTo(other.getClass().getName());
    }

    int lastComparison = 0;
    ThriftData typedOther = (ThriftData)other;

    lastComparison = Boolean.valueOf(isSetTitle()).compareTo(isSetTitle());
    if (lastComparison != 0) {
      return lastComparison;
    }
    lastComparison = TBaseHelper.compareTo(title, typedOther.title);
    if (lastComparison != 0) {
      return lastComparison;
    }
    lastComparison = Boolean.valueOf(isSetDetails()).compareTo(isSetDetails());
    if (lastComparison != 0) {
      return lastComparison;
    }
    lastComparison = TBaseHelper.compareTo(details, typedOther.details);
    if (lastComparison != 0) {
      return lastComparison;
    }
    lastComparison = Boolean.valueOf(isSetList_sample()).compareTo(isSetList_sample());
    if (lastComparison != 0) {
      return lastComparison;
    }
    lastComparison = TBaseHelper.compareTo(list_sample, typedOther.list_sample);
    if (lastComparison != 0) {
      return lastComparison;
    }
    return 0;
  }

  public void read(TProtocol iprot) throws TException {
    TField field;
    iprot.readStructBegin();
    while (true)
    {
      field = iprot.readFieldBegin();
      if (field.type == TType.STOP) {
        break;
      }
      _Fields fieldId = _Fields.findByThriftId(field.id);
      if (fieldId == null) {
        TProtocolUtil.skip(iprot, field.type);
      } else {
        switch (fieldId) {
          case TITLE:
            if (field.type == TType.STRING) {
              this.title = iprot.readString();
            } else {
              TProtocolUtil.skip(iprot, field.type);
            }
            break;
          case DETAILS:
            if (field.type == TType.STRING) {
              this.details = iprot.readString();
            } else {
              TProtocolUtil.skip(iprot, field.type);
            }
            break;
          case LIST_SAMPLE:
            if (field.type == TType.LIST) {
              {
                TList _list0 = iprot.readListBegin();
                this.list_sample = new ArrayList<String>(_list0.size);
                for (int _i1 = 0; _i1 < _list0.size; ++_i1)
                {
                  String _elem2;
                  _elem2 = iprot.readString();
                  this.list_sample.add(_elem2);
                }
                iprot.readListEnd();
              }
            } else {
              TProtocolUtil.skip(iprot, field.type);
            }
            break;
        }
        iprot.readFieldEnd();
      }
    }
    iprot.readStructEnd();

    // check for required fields of primitive type, which can't be checked in the validate method
    validate();
  }

  public void write(TProtocol oprot) throws TException {
    validate();

    oprot.writeStructBegin(STRUCT_DESC);
    if (this.title != null) {
      oprot.writeFieldBegin(TITLE_FIELD_DESC);
      oprot.writeString(this.title);
      oprot.writeFieldEnd();
    }
    if (this.details != null) {
      oprot.writeFieldBegin(DETAILS_FIELD_DESC);
      oprot.writeString(this.details);
      oprot.writeFieldEnd();
    }
    if (this.list_sample != null) {
      oprot.writeFieldBegin(LIST_SAMPLE_FIELD_DESC);
      {
        oprot.writeListBegin(new TList(TType.STRING, this.list_sample.size()));
        for (String _iter3 : this.list_sample)
        {
          oprot.writeString(_iter3);
        }
        oprot.writeListEnd();
      }
      oprot.writeFieldEnd();
    }
    oprot.writeFieldStop();
    oprot.writeStructEnd();
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder("ThriftData(");
    boolean first = true;

    sb.append("title:");
    if (this.title == null) {
      sb.append("null");
    } else {
      sb.append(this.title);
    }
    first = false;
    if (!first) sb.append(", ");
    sb.append("details:");
    if (this.details == null) {
      sb.append("null");
    } else {
      sb.append(this.details);
    }
    first = false;
    if (!first) sb.append(", ");
    sb.append("list_sample:");
    if (this.list_sample == null) {
      sb.append("null");
    } else {
      sb.append(this.list_sample);
    }
    first = false;
    sb.append(")");
    return sb.toString();
  }

  public void validate() throws TException {
    // check for required fields
  }

}




このソースを開発環境にコピーしておきます。





Voldemortのstores.xmlを編集



作成したThriftDataをserializerとして指定します。

%Voldemort%/config/single_node_cluster/config/stores.xml
を開いて、以下のように編集しました。


<stores>
  <store>
    <name>test</name>
    <persistence>bdb</persistence>
    <routing>client</routing>
    <replication-factor>1</replication-factor>
    <required-reads>1</required-reads>
    <required-writes>1</required-writes>
    <key-serializer>
      <type>string</type>
    </key-serializer>
    <value-serializer>
      <type>thrift</type>
      <schema-info>java=com.fc2.blog68.symfoware.voldemort.ThriftData,protocol=binary</schema-info>
    </value-serializer>
  </store>
</stores>




value-serializerのtypeに「thrift」
schema-infoに「java=com.fc2.blog68.symfoware.voldemort.ThriftData,protocol=binary」
と、作成したクラス名を指定します。

Voldemortが指定したcom.fc2.blog68.symfoware.voldemort.ThriftDataのクラスを
ロードしている必要があるのかな?と思っていましたが、単純にクラス名を
管理しているだけのようで、クラスファイルのコピーは不要でした。


編集が終わったら、Voldemortを再起動します。





開発環境にビルドパスを追加



Voldemort側の設定は終わりましたので、今度は開発環境の設定です。
serializerにthriftを使用するため、jarファイルをビルドパスに追加します。


追加するjarファイルは以下の3つ。


libthrift-0.2.0.jar
slf4j-api-1.5.6.jar
slf4j-log4j12-1.5.6.jar



これらのjarは、Voldemort/libにあるはずです。


最終的に、使用するjarファイルは以下の7つになります。


voldemort-0.80.1.jar
google-collect-1.0.jar
jdom-1.1.jar
log4j-1.2.15.jar
libthrift-0.2.0.jar
slf4j-api-1.5.6.jar
slf4j-log4j12-1.5.6.jar







サンプルプログラム



サンプルを作成し、動かしてみました。

■Sample.java


package com.fc2.blog68.symfoware.voldemort;

import java.util.ArrayList;
import java.util.List;

import voldemort.client.ClientConfig;
import voldemort.client.SocketStoreClientFactory;
import voldemort.client.StoreClient;
import voldemort.client.StoreClientFactory;

public class Sample {
    public static void main(String[] args) {
        
        String[] bootstrapUrls = new String[]{"tcp://192.168.1.250:6666"};
        
        ClientConfig cc = new ClientConfig();
        cc.setBootstrapUrls(bootstrapUrls);
        
        StoreClientFactory factory = new SocketStoreClientFactory(cc);
        
        //最初にキーの型、二番目に登録するデータの型を定義する
        StoreClient<String, ThriftData> client = factory.getStoreClient("test");
        
        client.delete("key");
        
        //登録用のオブジェクトを生成
        ThriftData data = new ThriftData();
        data.title = "日本語タイトルを設定";
        data.details = "日本語の詳細を設定してみます。";
        
        List<String> list = new ArrayList<String>();
        list.add("その1");
        list.add("その2");
        list.add("その3");
        data.list_sample = list;
        
        client.put("key", data);
        
        
        data = client.getValue("key");
        System.out.println(data.getTitle());
        System.out.println(data.getDetails());
        
        for (int i = 0; i < data.getList_sampleSize(); i++) {
            System.out.println(data.getList_sample().get(i));
        }
        
    }
}




動かしてみると・・・



[2010-04-18 15:38:01,821 voldemort.client.DefaultStoreClient] INFO bootstrapping metadata.
日本語タイトルを設定
日本語の詳細を設定してみます。
その1
その2
その3



狙い通りの動作になっています。




関連記事

テーマ:データベース - ジャンル:コンピュータ

  1. 2010/04/23(金) 12:11:55|
  2. Voldemort
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集
<<Debian + VoldemortにWindows + Pythonで接続する | ホーム | Voldemortのデータにオブジェクトを登録する方法(java-serialization使用)>>

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://symfoware.blog68.fc2.com/tb.php/386-4889b866
この記事にトラックバックする(FC2ブログユーザー)