我们有以下情况
给出以下两个实体
@Indexed
@Spatial(spatialMode = SpatialMode.HASH)
@Entity
@Table(name = "address")
Address{
@Field
@Basic
@Column(name = "state")
private String state;
@Field
@Basic
@Column(name = "town_city")
private String townCity;
@Field
@Longitude
@Basic
@Column(name = "x_coord")
private Double xCoord;
@Field
@Latitude
@Basic
@Column(name = "y_coord")
private Double yCoord;
}
和
@Indexed
@Entity
@Table(name = "person")
Person{
@Field
@Column(name = "weight")
private Double weight;
@Column(name = "age")
private Integer age;
@org.hibernate.annotations.Cache(usage =
org.hibernate.annotations.CacheConcurrencyStrategy.READ_WRITE)
@ManyToMany
@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
@JoinTable(name = "person_address",
joinColumns = {@JoinColumn(name = "person_id")},
inverseJoinColumns = {@JoinColumn(name = "address_id")})
private Set<Address> addressSet = new HashSet<>();
}
Getters和Setters其余字段省略
我们想返回搜索结果作为示例,该示例在给定位置的5KM半径内并且也在年龄范围内。
所以
FullTextSession fullTextSession = Search.getFullTextSession(entityManagerFactory.unwrap(SessionFactory.class).openSession());
this.queryBuilder = fullTextSession.getSearchFactory()
.buildQueryBuilder().forEntity(Person.class)
.overridesForField("identifiers.identifier_edge", "identifier_query_analyzer")
.get();
this.bool = queryBuilder.bool();
LocalDateTime lowerLocalDateTime = localDateTime.withYear(localDateTime.getYear() - upperAge);
lowerDate = Date.from(lowerLocalDateTime.atZone(ZoneId.systemDefault()).toInstant());
LocalDateTime upperLocalDateTime = localDateTime.withYear(localDateTime.getYear() - lowerAge);
upperDate = Date.from(upperLocalDateTime.atZone(ZoneId.systemDefault()).toInstant());
bool.must(getQueryBuilder().range().onField("datesOfBirth.dateOfBirth").from(lowerDate).to(upperDate).createQuery());
将为我们提供相关年龄段的人
我们有一个单独的查询来获取地址ID在给定点附近的半径内
public Set<Integer> getSpatialAddressResults(SpatialSearchCommand spatialSearchCommand) {
FullTextSession fullTextSession = Search.getFullTextSession(entityManagerFactory.unwrap(SessionFactory.class).openSession());
this.userSearchPreference = userSearchPreference;
this.queryBuilder = fullTextSession.getSearchFactory()
.buildQueryBuilder().forEntity(Address.class)
.get();
this.bool = queryBuilder.bool();
Set<Integer> addressIdSet = new HashSet<>();
bool.must(getQueryBuilder().spatial()
.within(spatialSearchCommand.getRadius(), Unit.KM).ofLatitude
(spatialSearchCommand.getLat()).andLongitude(spatialSearchCommand.getLng()).createQuery());
FullTextQuery fullTextQuery =
fullTextSession.createFullTextQuery(bool.createQuery(), Address.class)
.setProjection("addressId")
.initializeObjectsWith(ObjectLookupMethod.SECOND_LEVEL_CACHE,
DatabaseRetrievalMethod.QUERY);
List results = fullTextQuery.list();
for (Object result : results) {
Object[] arrayResult = (Object[]) result;
addressIdSet.add(((Integer) arrayResult[0]));
}
if (addressIdSet.size() == 0) {
addressIdSet.add(-1);
}
return addressIdSet;
}
我们如下使用(实际上,它们是在单独的类中完成的,但为简单起见,我只显示了相关代码)>
Set<Integer> localAddressIds = getSpatialAddressResults(new SpatialSearchCommand(userSearchPreference.getRadius(), userSearchPreference.getLat(), userSearchPreference.getLng())); if(localAddressIds.size() > 0){ BooleanJunction<BooleanJunction> localSquQueryBool = getQueryBuilder().bool(); for (Integer localAddressId : localAddressIds) { localSquQueryBool.should(getQueryBuilder().keyword().onField("currentLocation.address.indexId").matching(localAddressId).createQuery()); if(!personSearchCommand.getCurrentOnly()){ localSquQueryBool.should(getQueryBuilder().keyword().onField("locations.address.indexId").matching(localAddressId).createQuery()); } } bool.must(localSquQueryBool.createQuery()); }
问题是可能返回大量地址,这会导致BooleanQueryTooManyClauses:maxClauseCount设置为1024
问题实际上是避免对两个不同索引的实体进行合并查询以避免上述问题的最佳方法是什么。
[鉴于以下两个实体@Indexed @Spatial(spatialMode = SpatialMode.HASH)@Entity @Table(name =“ address”)Address {@Field @Basic @Column(name = ...
基本上,您正在尝试实施联接操作。正如您所看到的,在客户端进行加入的技术难题并不容易解决。