【问题标题】:Avro schema definition nesting typesAvro 模式定义嵌套类型
【发布时间】:2015-03-26 14:08:50
【问题描述】:

我对 Avro 相当陌生,并且正在阅读有关嵌套类型的文档。下面的示例运行良好,但模型中的许多不同类型都有地址。是否可以定义 address.avsc 文件并将其作为嵌套类型引用?如果可能的话,您能否更进一步,为客户提供地址列表?提前致谢。

{"namespace": "com.company.model",
  "type": "record",
  "name": "Customer",
  "fields": [
    {"name": "firstname", "type": "string"},
    {"name": "lastname", "type": "string"},
    {"name": "email", "type": "string"},
    {"name": "phone", "type": "string"},
    {"name": "address", "type":
      {"type": "record",
       "name": "AddressRecord",
       "fields": [
         {"name": "streetaddress", "type": "string"},
         {"name": "city", "type": "string"},
         {"name": "state", "type": "string"},
         {"name": "zip", "type": "string"}
       ]}
    }
  ]
}

【问题讨论】:

    标签: avro


    【解决方案1】:

    有4种可能的方式:

    1. ticket 中所述,将其包含在 pom 文件中。
    2. 在一个 avsc 文件中声明所有类型。
    3. 使用单个静态解析器,首先解析所有导入,然后解析实际数据类型。
    4. (这是一个 hack)使用 avdl 文件并使用像 https://avro.apache.org/docs/1.7.7/idl.html#imports 这样的导入。不过,IDL 是为 RPC 调用而设计的。

    2 的示例。在单个 avsc 文件中声明所有类型。 还回答地址上的数组声明。

    [
    {
        "type": "record",
        "namespace": "com.company.model",
        "name": "AddressRecord",
        "fields": [
            {
                "name": "streetaddress",
                "type": "string"
            },
            {
                "name": "city",
                "type": "string"
            },
            {
                "name": "state",
                "type": "string"
            },
            {
                "name": "zip",
                "type": "string"
            }
        ]
    },
    {
        "namespace": "com.company.model",
        "type": "record",
        "name": "Customer",
        "fields": [
            {
                "name": "firstname",
                "type": "string"
            },
            {
                "name": "lastname",
                "type": "string"
            },
            {
                "name": "email",
                "type": "string"
            },
            {
                "name": "phone",
                "type": "string"
            },
            {
                "name": "address",
                "type": {
                    "type": "array",
                    "items": "com.company.model.AddressRecord"
                }
            }
        ]
    },
    {
        "namespace": "com.company.model",
        "type": "record",
        "name": "Customer2",
        "fields": [
            {
                "name": "x",
                "type": "string"
            },
            {
                "name": "y",
                "type": "string"
            },
            {
                "name": "address",
                "type": {
                    "type": "array",
                    "items": "com.company.model.AddressRecord"
                }
            }
        ]
    }
    ]
    

    3 的示例。使用单个静态解析器

    Parser parser = new Parser(); // Make this static and reuse
    parser.parse(<location of address.avsc file>);
    parser.parse(<location of customer.avsc file>);
    parser.parse(<location of customer2.avsc file>);
    

    如果我们想要持有 Schema,也就是说,如果我们想要创建新记录,我们可以这样做 https://avro.apache.org/docs/1.5.4/api/java/org/apache/avro/Schema.Parser.html#getTypes() 获取模式的方法 或

    Parser parser = new Parser(); // Make this static and reuse
    Schema addressSchema =parser.parse(<location of address.avsc file>);
    Schema customerSchema=parser.parse(<location of customer.avsc file>);
    Schema customer2Schema =parser.parse(<location of customer2.avsc file>); 
    

    【讨论】:

    • 不清楚如何使用示例 #3 中的解析器。创建完成后,如何创建记录(空白记录,不反序列化)
    • @RedBullet 我已经编辑了我的答案以澄清您的疑问。希望现在很清楚。
    • 在 #2 中,您的根类型是 UNION,对吗?那么这将允许用户将这些顶级类型中的任何一个序列化为根对象吗?这有点不幸,因为如果您只想在顶层序列化 Customer 对象,您无法真正让它以这种方式工作。
    • 我正在尝试选项 2 - 但是当我使用它时出现错误 - 你能确认它应该像 {"name": "address", "type": "com.company.model.AddressRecord"}
    【解决方案2】:

    只是为了添加到@Princey James 的答案中,嵌套类型必须在使用之前定义。

    【讨论】:

    • 您应该将该消息作为评论留在 Princey James 答案下,因为它不是问题的完整答案。
    • 我没有为该答案添加评论所需的 50 名声望。
    【解决方案3】:

    其他添加到@Princey James

    使用 2 的示例。在单个 avsc 文件中声明所有类型。

    它适用于序列化和反序列化代码生成

    但是序列化和反序列化没有代码生成 不起作用

    你会得到 org.apache.avro.AvroRuntimeException: Not a record schema: [{"type":" ...

    代码生成的工作示例:

      @Test
      public void avroWithCode() throws IOException {
    
        UserPerso UserPerso3 = UserPerso.newBuilder()
                                        .setName("Charlie")
                                        .setFavoriteColor("blue")
                                        .setFavoriteNumber(null)
                                        .build();
    
        AddressRecord adress = AddressRecord.newBuilder()
                                            .setStreetaddress("mo")
                                            .setCity("Paris")
                                            .setState("IDF")
                                            .setZip("75")
                                            .build();
    
        ArrayList<AddressRecord> li = new ArrayList<>();
        li.add(adress);
    
        Customer cust = Customer.newBuilder()
                                .setUser(UserPerso3)
                                .setPhone("0101010101")
                                .setAddress(li)
                                .build();
    
        String fileName = "cust.avro";
    
        File a = new File(fileName);
    
        DatumWriter<Customer> customerDatumWriter = new SpecificDatumWriter<>(Customer.class);
        DataFileWriter<Customer> dataFileWriter = new DataFileWriter<>(customerDatumWriter);
        dataFileWriter.create(cust.getSchema(), new File(fileName));
        dataFileWriter.append(cust);
        dataFileWriter.close();
    
        DatumReader<Customer> custDatumReader = new SpecificDatumReader<>(Customer.class);
        DataFileReader<Customer> dataFileReader = new DataFileReader<>(a, custDatumReader);
        Customer cust2 = null;
        while (dataFileReader.hasNext()) {
          cust2 = dataFileReader.next(cust2);
          System.out.println(cust2);
        }
      }
    

    没有:

      @Test
      public void avroWithoutCode() throws IOException {
    
        Schema schemaUserPerso = new Schema.Parser().parse(new File("src/main/resources/avroTest/user.avsc"));
        Schema schemaAdress = new Schema.Parser().parse(new File("src/main/resources/avroTest/user.avsc"));
        Schema schemaCustomer = new Schema.Parser().parse(new File("src/main/resources/avroTest/user.avsc"));
    
        System.out.println(schemaUserPerso);
    
        GenericRecord UserPerso3 = new GenericData.Record(schemaUserPerso);
        UserPerso3.put("name", "Charlie");
        UserPerso3.put("favorite_color", "blue");
        UserPerso3.put("favorite_number", null);
    
        GenericRecord adress = new GenericData.Record(schemaAdress);
    
        adress.put("streetaddress", "mo");
        adress.put("city", "Paris");
        adress.put("state", "IDF");
        adress.put("zip", "75");
    
        ArrayList<GenericRecord> li = new ArrayList<>();
        li.add(adress);
    
        GenericRecord cust = new GenericData.Record(schemaCustomer);
    
        cust.put("user", UserPerso3);
        cust.put("phone", "0101010101");
        cust.put("address", li);
    
        String fileName = "cust.avro";
    
        File file = new File(fileName);
    
        DatumWriter<GenericRecord> datumWriter = new GenericDatumWriter<>(schemaCustomer);
        DataFileWriter<GenericRecord> dataFileWriter = new DataFileWriter<>(datumWriter);
        dataFileWriter.create(schemaCustomer, file);
        dataFileWriter.append(cust);
        dataFileWriter.close();
    
        File a = new File(fileName);
    
        DatumReader<GenericRecord> datumReader = new GenericDatumReader<>(schemaCustomer);
        DataFileReader<GenericRecord> dataFileReader = new DataFileReader<>(a, datumReader);
        GenericRecord cust2 = null;
        while (dataFileReader.hasNext()) {
          cust2 = dataFileReader.next(cust2);
          System.out.println(cust2);
    
        }
      }
    

    【讨论】:

      猜你喜欢
      • 2017-04-12
      • 2014-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-15
      • 2022-01-03
      • 2016-10-23
      • 2015-01-26
      相关资源
      最近更新 更多