我正在考虑在hadoop上使用AVRO。但我关心的是大型数据结构的序列化以及如何向(数据)类添加方法。
示例(摘自http://blog.voidsearch.com/bigdata/apache-avro-in-practice/)显示了facebook用户的模型。
{
"namespace": "test.avro",
"name": "FacebookUser",
"type": "record",
"fields": [
{"name": "name", "type": "string"},
...,
{"name": "friends", "type": "array", "items": "FacebookUser"}
]
}
avro是否在此模型中序列化了facebookuser的完整社交图?
[也就是说,如果我想序列化一个用户,序列化是否包括所有朋友和他们的朋友等等?]
如果答案是肯定的,我宁愿存储ID的朋友而不是引用,以便在需要时查看我的应用程序。在这种情况下,我希望能够添加一个返回实际朋友而不是ID的方法。
如何包装/扩展生成的AVRO java类以添加方法?
(也用于添加返回例如friend-count的方法)
答案 0 :(得分:3)
关于第二个问题:如何包装/扩展生成的AVRO java类以添加方法?
您可以使用AspectJ将新方法注入现有/生成的类中。 AspectJ仅在编译时需要。方法如下所示。
将人员记录定义为Avro IDL( person.avdl ):
@namespace("net.tzolov.avro.extend")
protocol PersonProtocol {
record Person {
string firstName;
string lastName;
}
}
使用maven和avro-maven-plugin从AVDL生成java源:
<dependency>
<groupId>org.apache.avro</groupId>
<artifactId>avro</artifactId>
<version>1.6.3</version>
</dependency>
......
<plugin>
<groupId>org.apache.avro</groupId>
<artifactId>avro-maven-plugin</artifactId>
<version>1.6.3</version>
<executions>
<execution>
<id>generate-avro-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>idl-protocol</goal>
</goals>
<configuration>
<sourceDirectory>src/main/resources/avro</sourceDirectory>
<outputDirectory>${project.build.directory}/generated-sources/java</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
以上配置假设 person.avid 文件位于 src / main / resources / avro 中。源在 target / generated-sources / java 中生成。
Generated Person.java有两个方法:getFirstName()和getLastName()。如果您想用另一种方法扩展它: getCompleteName() = firstName + lastName,那么您可以使用以下方面注入此方法:
package net.tzolov.avro.extend;
import net.tzolov.avro.extend.Person;
public aspect PersonAspect {
public String Person.getCompleteName() {
return this.getFirstName() + " " + this.getLastName();
}
}
使用aspectj-maven-plugin maven插件将此方面与生成的代码
编织在一起<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.12</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
</dependency>
....
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.2</version>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.12</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.6.12</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<source>6</source>
<target>6</target>
</configuration>
</plugin>
结果:
@Test
public void testPersonCompleteName() throws Exception {
Person person = Person.newBuilder()
.setFirstName("John").setLastName("Atanasoff").build();
Assert.assertEquals("John Atanasoff", person.getCompleteName());
}
答案 1 :(得分:2)
我试图先回答第一个问题:
据我所知,AVRO不是为了存储非层次结构而构建的。它也没有对象id的表示法。它可以存储数组,基元类型的记录或它们的任何组合。你所参考的对象图表的能力是Java序列化的能力AVRO lacing
因此,要存储一些图形,您应该引入自己的对象ID,并明确地将它们分配给某些字段。
您可以在此处查看getSchema方法:http://www.java2s.com/Open-Source/Java/Database-DBMS/hadoop-0.20.1/org/apache/avro/reflect/ReflectData.java.htm
它很简单......这是AVRO通过java类生成模式的一种方式。
关于第二个问题 - 我不认为修改生成的代码是个好主意。我建议使用你想要添加的所有方法/数据来创建类,并将AVRO生成的“数据”类作为成员放在那里。
同时,我认为技术上扩展生成的类应该没问题。
答案 2 :(得分:0)
除了尝试使用Avro解决这些问题之外,这可能无法正常工作(我的猜测是扩展生成的类无论你怎么尝试都不会很好),你可以考虑使用普通的JSON(除非你对Avro有特殊要求) )。 许多库支持任意POJO映射;而一些(如Jackson)也支持基于对象ID的序列化(使用2.0.0)。