Hibernate поиск ManyToMany с пространственным поиском - PullRequest
0 голосов
/ 28 января 2019

У меня есть объект A с Hibernate Search @Spatial, например:

@Entity
@Spatial(spatialMode = SpatialMode.HASH)
@Indexed
public class A {

    @Id
    @GeneratedValue(generator = "uuid2")
    private UUID id;

    private Double latitude;

    private Double longitude;

    @Spatial(spatialMode = SpatialMode.HASH)
    @SortableField
    public Coordinates getLocation() {
        return new Coordinates() {
            @Override
            public Double getLatitude() {
                return latitude;
            }

            @Override
            public Double getLongitude() {
                return longitude;
            }
        };
    }

    @ManyToMany(fetch = FetchType.EAGER)
    @IndexedEmbedded
    private Set<B> multipleB = new HashSet<>();
}

Объект A имеет отношение ManyToMany с объектом B. Объект A имеет пространственную информацию, которая важна для объекта B. Теперь яхочу выполнить пространственный запрос для объекта B, который использует информацию о местоположении объекта A.

@Entity
@Indexed
public class B {
    @Id
    @GeneratedValue(generator = "uuid2")
    private UUID id;

    @ManyToMany
    @ContainedIn
    private Set<A> multipleA = new HashSet<>();
}

Я пытался выполнить запрос для объекта B следующим образом:

QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(B.class).get();

    Query luceneQuery = qb.
            spatial()
            .onField("multipleA.location")
            .within(kmRadius, Unit.KM)
            .ofLatitude(centerLatitude)
            .andLongitude(centerLongitude)
            .createQuery();

ОднакоПроблема в том, что когда я делаю такой запрос, я получаю следующее исключение:

The field 'B#multipleA.location' used for the spatial query is not configured as spatial field. Check the proper use of @Spatial respectively SpatialFieldBridge.

Есть ли способ выполнить пространственные запросы для объектов типа B, которые используют пространственные данные из подключенных объектовA с @ManyToMany?

Для моих запросов также было бы приемлемо, если бы один и тот же объект B возвращался несколько раз для каждого подключенного объекта A (как это было бы при объединении).

Пример (a_1 - ближайший объект A)

Database: b_1 -> (a_1, a_2), b_2 -> (a_1), b_3 -> (a_2, a_3)

Результат запроса:

b_1 (a_1 is the closest)
b_2 (a_1)
b_1 (a_2 is the second closest)
b_3 (a_2)
b_3 (a_3)

1 Ответ

0 голосов
/ 28 января 2019

Многозначные местоположения не поддерживаются в Hibernate Search;даже если вам удастся проиндексировать его, запрос просто не будет работать должным образом (он будет смешивать широту и долготу из разных точек).

Единственный способ увидеть эту работу - это смоделировать ваши многочисленные-в-многих связать как сущность, проиндексировать эту сущность и запросить ее вместо B.

Также обратите внимание, что ошибка, которую вы получаете, связана с другой проблемой: поле, на которое вы нацеливаетесь, делаетне существует.Если вы хотите, чтобы он существовал, вам нужно добавить @IndexedEmbedded в B#multipleA.

. Вот что должно работать лучше:

@Entity
@Spatial(spatialMode = SpatialMode.HASH)
@Indexed
public class A {

    @Id
    @GeneratedValue(generator = "uuid2")
    private UUID id;

    private Double latitude;

    private Double longitude;

    @Latitude
    public Double getLatitude() {
        return latitude;
    }

    @Longitude
    public Double getLongitude() {
        return longitude;
    }

    @OneToMany(mappedBy = "a")
    @ContainedIn
    private Set<AToB> multipleB = new HashSet<>();
}

@Entity
@Indexed
public class AToB {
    @Id
    @GeneratedValue(generator = "uuid2")
    private UUID id;

    @ManyToOne
    @IndexedEmbedded(includePaths = "location") // includePaths will be necessary to avoid infinite recursion if you really want an @IndexedEmbedded from A to B
    private A a;

    @ManyToOne
    @IndexedEmbedded
    private B b;
}

@Entity
public class B {
    @Id
    @GeneratedValue(generator = "uuid2")
    private UUID id;

    @OneToMany(mappedBy = "b")
    @ContainedIn
    private Set<AToB> multipleA = new HashSet<>();
}

Затем запросите вот так:1013 *

QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(AToB.class).get();

    Query luceneQuery = qb.
            spatial()
            .onField("a.location")
            .within(kmRadius, Unit.KM)
            .ofLatitude(centerLatitude)
            .andLongitude(centerLongitude)
            .createQuery();
...