【问题标题】:How does Apache AVRO serialize (large) data-structuresApache AVRO 如何序列化(大型)数据结构
【发布时间】:2012-03-27 11:11:44
【问题描述】:

我正在研究在 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 类以添加方法?

(还添加返回例如朋友计数的方法)

【问题讨论】:

    标签: java code-generation avro


    【解决方案1】:

    关于第二个问题:如何包装/扩展生成的 AVRO java 类以添加方法?

    您可以使用 AspectJ 将新方法注入现有/生成的类。只有在编译时才需要 AspectJ。方法如下所示。

    将 Person 记录定义为 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());
    }
    

    【讨论】:

      【解决方案2】:

      我想先回答第一个问题:
      据我所知,AVRO 并不是为了存储非分层的东西而构建的。它也没有对象 ID 的表示法。它可以存储数组、原始类型的记录或它们的任何组合。遍历您所指的对象图的能力是 AVRO 结合的 Java 序列化能力
      因此,要存储一些图形,您应该介绍自己的对象 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 生成的“数据”类作为成员。
      同时,我认为从技术上扩展生成的类应该没问题。

      【讨论】:

        【解决方案3】:

        除了尝试使用 Avro 解决这些问题之外,这可能行不通(我的猜测是,无论您如何尝试扩展生成的类都无法正常工作),您可以考虑使用纯 JSON(除非您对 Avro 有特定要求)。 许多库支持任意 POJO 映射;还有一些(比如Jackson)也支持基于对象ID的序列化(2.0.0)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-08-16
          • 1970-01-01
          • 1970-01-01
          • 2018-07-20
          • 1970-01-01
          • 2012-11-27
          • 1970-01-01
          • 2021-11-15
          相关资源
          最近更新 更多