Получение так много предупреждений при использовании List с настраиваемым Java-классом POJO в apache beam java

Я новичок в Apache beam, я использую луч Apache и в качестве бегуна использую поток данных в GCP. Я получаю следующую ошибку при выполнении конвейера.

coder of type class org.apache.beam.sdk.coders.ListCoder has a #structuralValue method which does not return true when the encoding of the elements is equal. Element [Person [businessDay=01042020, departmentId=101, endTime=2020-04-01T09:06:02.000Z, companyId=242, startTime=2020-04-01T09:00:33.000Z], Person [businessDay=01042020, departmentId=101, endTime=2020-04-01T09:07:47.000Z, companyId=242, startTime=2020-04-01T09:06:03.000Z], Person [businessDay=01042020, departmentId=101, endTime=2020-04-01T09:48:25.000Z, companyId=242, startTime=2020-04-01T09:07:48.000Z]]

PCollection похож на PCollection>> и PCollection>>>

Я реализовал Person как сериализуемый класс POJO и также переопределил метод equals и hash. Но я думаю, что мне нужно написать собственный ListCoder для человека и зарегистрироваться в конвейере. Я не знаю, как решить эту проблему, пожалуйста, помогите.

1 ответ

Решение

Вот рабочий пример. Если вы клонируете репо, подplayground корневой каталог, запустить ./gradlew run, тогда вы можете проверить эффект. Вы также можете работать с./gradlew run --args='--runner=DataflowRunner --project=$YOUR_PROJECT_ID --tempLocation=gs://xxx/staging --stagingLocation=gs://xxx/staging' чтобы запустить его в Dataflow.

В Person class должен выглядеть так, если вы строите его с нуля:

class Person implements Serializable {
  public Person(
      String businessDay,
      String departmentId,
      String companyId
  ) {
    this.businessDay = businessDay;
    this.departmentId = departmentId;
    this.companyId = companyId;
  }

  public String companyId() {
    return companyId;
  }

  public String businessDay() {
    return businessDay;
  }

  public String departmentId() {
    return departmentId;
  }

  @Override
  public boolean equals(Object other) {
    if (this == other) {
      return true;
    }
    if (other == null) {
      return false;
    }
    if (getClass() != other.getClass()) {
      return false;
    }
    Person otherPerson = (Person) other;
    return this.businessDay.equals(otherPerson.businessDay)
        && this.departmentId.equals(otherPerson.departmentId)
        && this.companyId.equals(otherPerson.companyId);
  }

  @Override
  public int hashCode(){
    return Objects.hash(this.businessDay, this.departmentId, this.companyId);
  }

  private final String businessDay;
  private final String departmentId;
  private final String companyId;
}

я рекомендую

  • использование AutoValue вместо создания POJO с нуля. Вот несколько примеров. Вы можете просмотреть весь проект здесь. Преимущество в том, что вам не нужно реализовыватьequals а также hashCode с нуля каждый раз, когда вы создаете новый тип объекта.

  • В KV, если ключ является итерируемым, например List, оберните его в объект и явно детерминированно сериализуйте его (пример), поскольку сериализация в Java недетерминирована.