2016-11-24 2 views
4

저는 Avro와 협력 중이며 GenericRecord입니다. 그것으로부터 clientId, deviceName, holder을 추출하고 싶습니다. Avro 스키마에서 clientId은 Integer이고 deviceName은 String이고 holder은 Map입니다. 아 브로 스키마의GenericRecord에서 입력 된 값을 얻는 방법은 무엇입니까?

{ 
    "name" : "clientId", 
    "type" : [ "null", "int" ], 
    "doc" : "hello" 
} 

deviceName : 다음 브로 스키마

{ 
    "name" : "deviceName", 
    "type" : [ "null", "string" ], 
    "doc" : "test" 
} 

holder 다음 브로 스키마

clientId

{ 
    "name" : "holder", 
    "type" : { 
     "type" : "map", 
     "values" : "string" 
    } 
} 

내 질문은 - 무엇이입니다 입력 된 값을 검색하는 권장 방법 개체?

아래 코드에서 payloadGenericRecord이며 우리는이 스키마에서 avro 스키마를 얻을 수 있습니다. 이것은 내가 지금하고있는 일이며, 모든 것을 String으로 추출한다. 하지만 어떻게하면 입력 된 값을 얻을 수 있을까요? 어떤 방법이 있습니까? avro 스키마에있는 데이터 유형이 무엇이든 상관없이 추출해야합니다.

public static void getData(GenericRecord payload) { 
    String id = String.valueOf(payload.get("clientId")); 
    String name = String.valueOf(payload.get("deviceName")); 

    // not sure how to get maps here 
    } 

그래서 나는 GenericRecord에서 자바지도 Map<String, String> 같은 문자열로 정수로 clientId, deviceNameholder을 추출 할? 그렇게하는 가장 좋은 방법은 무엇입니까? 일반 레코드와 스키마를 통해 입력 된 모든 변환을 수행하는 유틸리티를 작성할 수 있습니까?

+0

세 가지'payload.get' 호출에서 반환되는 객체 유형은 무엇입니까? – qxz

+0

@qxz 의미? 나는 이해하지 못했다. 그것은 모든 것을 객체로 반환합니다. 그리고 나서 그것을 캐스팅해야합니다. 우리는 페이로드에서 스키마를 사용하고 결과를 변환하고 반환하는 유틸리티를 작성할 수 있다고 생각합니다. – john

+0

각각에 대해'payload.get ("..."). getClass()를 인쇄 해보십시오.getCanonicalName()'객체의 타입을 확인한다 – qxz

답변

1

당신은 intInteger에, Utf8string 값을 캐스팅 할 수 있어야하고, Map<Utf8, Utf8>map. 이것은 ClassCastException없이 작동합니다 : 일반적으로

public static void getData(GenericRecord payload) { 
    int id = (Integer) payload.get("clientId"); 
    String name = payload.get("deviceName").toString(); // calls Utf8.toString 
    Map<Utf8, Utf8> holder = (Map<Utf8, Utf8>) payload.get("holder"); 

    ... 
} 

을, 당신이 캐스트를 할 수 있다고 생각 :

  • 프리미티브 (등 Integer, Double) 자신의 박스 버전
  • string가 될 될 Utf8
  • bytesjava.nio.ByteBuffer
  • arrayjava.util.Collection
  • map하게 당신이 방법을 시도 할 수 java.util.Map<Utf8, [value type]>
1

된다. 강력한 구현을 위해 코드를 고려해야합니다. generation using schema compilation.

package stackoverflow; 

import static org.hamcrest.CoreMatchers.is; 
import static org.junit.Assert.assertThat; 

import java.util.Arrays; 
import java.util.HashMap; 
import java.util.Map; 

import org.apache.avro.AvroTypeException; 
import org.apache.avro.Schema; 
import org.apache.avro.Schema.Field; 
import org.apache.avro.Schema.Type; 
import org.apache.avro.generic.GenericData.Record; 
import org.apache.avro.generic.GenericRecord; 
import org.apache.avro.util.Utf8; 
import org.junit.Test; 

// Just for demonistration; not robust implementation 
public class GenericRecordType { 
    @Test 
    public void testName() throws Exception { 
     Schema schema = buildSchema(); 

     GenericRecord record = new Record(schema); 
     record.put("clientId", 12); 
     record.put("deviceName", "GlassScanner"); 
     record.put("holder", new HashMap<>()); 

     Integer value = IntField.clientId.getValue(record); 
     String deviceName = StringField.deviceName.getValue(record); 
     Map<String, String> mapString = MapOfStringField.holder.getValue(record); 

     assertThat(deviceName, is("GlassScanner")); 
     assertThat(value, is(12)); 
     assertThat(mapString.size(), is(0)); 
    } 

    private Schema buildSchema() { 
     Field clientId = new Field("clientId", Schema.create(Type.INT), "hello", (Object) null); 
     Field deviceName = new Field("deviceName", Schema.create(Type.STRING), "hello", (Object) null); 
     Field holder = new Field("holder", Schema.createMap(Schema.create(Type.STRING)), null, (Object) null); 
     Schema schema = Schema.createRecord(Arrays.asList(clientId, deviceName, holder)); 
     return schema; 
    } 

    public static interface TypedField<T> { 
     String name(); 

     public T getValue(GenericRecord record); 

    } 

    public static enum StringField implements TypedField<String> { 
     deviceName; 

     @Override 
     public String getValue(GenericRecord record) { 
      String typed = null; 
      Object raw = record.get(name()); 
      if (raw != null) { 
       if (!(raw instanceof String || raw instanceof Utf8)) { 
        throw new AvroTypeException("string type was epected for field:" + name()); 
       } 
       typed = raw.toString(); 
      } 
      return typed; 
     } 

    } 

    public static enum IntField implements TypedField<Integer> { 
     clientId; 

     private IntField() { 
     } 

     @Override 
     public Integer getValue(GenericRecord record) { 
      Integer typed = null; 
      Object raw = record.get(name()); 
      if (raw != null) { 
       if (!(raw instanceof Integer)) { 
        throw new AvroTypeException("int type was epected for field:" + name()); 
       } 
       typed = (Integer) raw; 
      } 
      return typed; 
     } 

    } 

    public static enum MapOfStringField implements TypedField<Map<String, String>> { 
     holder; 

     @Override 
     @SuppressWarnings("unchecked") 
     public Map<String, String> getValue(GenericRecord record) { 
      Map<String, String> typed = null; 
      Object raw = record.get(name()); 
      if (raw != null) { 
       if (!(raw instanceof Map)) { 
        throw new AvroTypeException("map type was epected for field:" + name()); 
       } 
       typed = (Map<String, String>) raw; 
      } 
      return typed; 
     } 
    } 

} 
관련 문제