#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
тем, как вы можете добиться удаления несопоставимых объектов, я хотел бы знать. Возможно, вы также можете опубликовать ответ?