Создание EntityIterable из нескольких объектов Entity

#java #geospatial #xodus

#java #геопространственный #xodus

Вопрос:

Я пытаюсь реализовать фильтр «поблизости» с помощью Xodus, используя этот код:

 AtomicReference<EntityIterable> referenceToScope = ...;
PropertyNearbyCondition propertyNearbyCondition = (PropertyNearbyCondition) entityCondition;
String propertyName = propertyNearbyCondition.propertyName();
Double longitude = propertyNearbyCondition.longitude();
Double latitude = propertyNearbyCondition.latitude();
Double distance = propertyNearbyCondition.distance();
EntityIterable entities =
    referenceToScope.get().intersect(txn.findWithProp(entityType, propertyName));
List<Entity> entityList = new ArrayList<>();
entities.forEach(entity -> {
  GeoPoint reference = (GeoPoint) entity.getProperty(propertyName);
  double instantaneousDistance =
      MathHelper.distFrom(latitude, longitude, reference.getLatitude(),
  reference.getLatitude());
  if (distance >= instantaneousDistance) {
    entityList.add(entity);
  }
});


EntityIterable scoped = referenceToScope.get().intersect(build(entityList));

  
 EntityIterable build(List<Entity> entityList) {
   // TODO: Build a new EntityIterable from the entityList
}
  

Алгоритм может быть не самым лучшим, но главный вопрос здесь заключается в том, как создать новый EntityIterable на основе нескольких объектов Entity? Возможно ли это?

Мое решение в основном собирать «близлежащие» объекты состоит в том, чтобы перебирать все объекты с пользовательским GeoPoint свойством, а затем для каждого найденного объекта сравнивать расстояние до его свойства GeoPoint, и если это попадание, то все эти объекты должны быть собраны в один EntityIterable.

Как вы создаете a EntityIterable из списка Entity объектов?

Обновить:

Пошаговое объяснение того, как это работает:

Этот приведенный ниже код получает все объекты с заданным именем свойства, например geoLocation

 EntityIterable entities =
    referenceToScope.get().intersect(txn.findWithProp(entityType, propertyName));
  

Затем для всех объектов с таким свойством геолокации, например, выполните итерацию по нему, чтобы вычислить, соответствует ли оно целевому расстоянию:

 List<Entity> entityList = new ArrayList<>();
entities.forEach(entity -> {
   // compute the distance target
});
  

Добавление объекта в новый List , если он соответствует цели.

Отсюда, что нужно сделать, это либо удалить все объекты в EntityIterable entities , которые не равны идентификаторам сопоставленных объектов в entityList , ЛИБО пересекать эти сопоставленные объекты с referenceToScope.get() , а не с EntityIterable entities (просто чтобы избежать путаницы, эта entities итерация является только временной)

Комментарии:

1. ps. будет ли этот подход проблемой производительности с Xodus?

2. и причиной создания a EntityIterable является создание контекста с ограниченной областью действия, поскольку этот код является лишь частью цепочки других условий свойства, которые в основном находятся в той же области действия EntityIterable , например, это связано с PropertyLocalTimeRangeCondition -> PropertyNearbyCondition -> PropertyMinMaxCondition

3. Почему вы это делаете referenceToScope.get().intersect(build(entityList)) ? EntityList уже является пересечением с referenceToScope, верно? Если вам не нужно пересекать result или выполнять с ним какие-либо другие операции, то, вероятно, вам не нужно создавать EntityIterable из результата?

4. @VyacheslavLukianov entityList является вычисляемым подмножеством этого EntityIterable entities = referenceToScope.get().intersect(txn.findWithProp(entityType, propertyName)); , потому что этот entities содержит только все объекты Xodus, которые имеют указанное propertyName, он не исключает объекты, которые не соответствуют целевому расстоянию, что является основной причиной создания отдельного списка. Если мы не можем вычислить в Xodus методы поиска, если данное географическое местоположение находится в пределах диапазона. Я пытаюсь, но это кажется невозможным с помощью метода find min max. Итак, мое решение — вычислять извне.

5. Пожалуйста, внимательно прочитайте. Нет необходимости пересекать referenceToScope.get() что-либо дважды. Это referenceToScope.get().intersect(build(entityList)) не меняет результат (EntityList). Следовательно, в вашем коде вам не нужна эта build() функция. Как правило, 99,99% случаев вычислений через EntityStore можно выразить как двухэтапный процесс: 1) подготовить EntityIterable экземпляр с помощью API; 2) вручную отфильтровать результат (в вашем случае фильтровать точки). После этого вам больше не нужен EntityIterable, сериализуйте результат (список) как сетевой вывод или что-то еще.

Ответ №1:

Вот как это решить:

 entities.forEach(entity -> {
  GeoPoint reference = (GeoPoint) entity.getProperty(propertyName);
  double instantaneousDistance =
      MathHelper.distFrom(latitude, longitude, reference.getLatitude(),
  reference.getLatitude());
  if (distance < instantaneousDistance) {
    referenceToScope.set(referenceToScope.get().minus(txn.getSingletonIterable(entity)));
  }
});
  

Это эффективно удалит все объекты, которые не соответствуют целевому расстоянию.

Комментарии:

1. Да, вы также можете использовать union синглтоны, но это в основном плохая идея из-за возможного влияния на производительность. Я пытаюсь объяснить автору, что в большинстве случаев нет необходимости преобразовывать результат, представленный как List<Entity> EntityIterable .

2. @VyacheslavLukianov если не пересекается с getSingletonIterable тем, как вы можете добиться удаления несопоставимых объектов, я хотел бы знать. Возможно, вы также можете опубликовать ответ?