elasticsearch 在不同索引上组合hibernate搜索查询的最佳方法,elasticsearch,lucene,hibernate-search,elasticsearch,Lucene,Hibernate Search" /> elasticsearch 在不同索引上组合hibernate搜索查询的最佳方法,elasticsearch,lucene,hibernate-search,elasticsearch,Lucene,Hibernate Search" />

elasticsearch 在不同索引上组合hibernate搜索查询的最佳方法

elasticsearch 在不同索引上组合hibernate搜索查询的最佳方法,elasticsearch,lucene,hibernate-search,elasticsearch,Lucene,Hibernate Search,我们有以下情况 鉴于以下两个实体 @Indexed @Spatial(spatialMode = SpatialMode.HASH) @Entity @Table(name = "address") Address{ @Field @Basic @Column(name = "state") private String state; @Field @Basic @Column(name = "town_city") priva

我们有以下情况

鉴于以下两个实体

@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;

}

这将给我们提供相关年龄范围内的人

我们有一个单独的查询来获取给定点周围半径内的地址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;

}
public Set 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 addressIdSet=new HashSet();
bool.must(getQueryBuilder().spatial())
.在(spatialSearchCommand.getRadius(),单位为.KM.)的纬度范围内
(spatialSearchCommand.getLat())和经度(spatialSearchCommand.getLng()).createQuery());
FullTextQuery FullTextQuery=
fullTextSession.createFullTextQuery(bool.createQuery(),Address.class)
.setProjection(“addressId”)
.initializeObjectsWith(ObjectLookupMethod.SECOND_LEVEL_缓存,
DatabaseRetrievalMethod.QUERY);
List results=fullTextQuery.List();
用于(对象结果:结果){
对象[]arrayResult=(对象[])结果;
addressIdSet.add(((整数)arrayResult[0]);
}
如果(addressIdSet.size()==0){
addressIdSet.add(-1);
}
返回地址集;
}
我们使用的方法如下(实际上,这些方法是在单独的类中完成的,但为了简单起见,我刚刚展示了相关的代码

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());
    }
Set localAddressIds=getSpatialAddressResults(新的SpatialSearchCommand(userSearchPreference.getRadius()、userSearchPreference.getLat()、userSearchPreference.getLng());
if(localAddressIds.size()>0){
BooleanJunction localSquQueryBool=getQueryBuilder().bool();
for(整数localAddressId:localAddressId){
localSquQueryBool.should(getQueryBuilder().keyword().onField(“currentLocation.address.indexId”).matching(localAddressId.createQuery());
如果(!personSearchCommand.getCurrentOnly()){
localSquQueryBool.should(getQueryBuilder().keyword().onField(“locations.address.indexId”).matching(localAddressId.createQuery());
}
}
bool.must(localSquQueryBool.createQuery());
}
问题是可能会返回大量地址,从而导致BooleanQueryToManyClauses:maxClauseCount设置为1024


真正的问题是,组合两个不同索引实体上的查询以避免上述问题的最佳方法是什么。

本质上,您正在尝试实现联接操作。正如您所看到的,联接存在一些技术难题,这些难题在客户端很难解决

通常,Elasticsearch和Lucene中推荐的方法是尽可能避免连接。相反,您将取消模式规范化:在代表每个人的文档中,嵌入每个地址的副本。然后,您将能够在针对
索引的单个查询中表达所有约束。 这是通过使用
@IndexedEmbedded
注释
Person
中的
addresses
属性来完成的

现在,正如您所想象的,这种去规范化是有代价的:每当地址发生更改时,Hibernate搜索都必须更新相关人员。 为此,您需要将
列表
属性添加到
地址
类中,并使用
@ContainedIn
对其进行注释,以便Hibernate Search能够在地址被修改时获取要重新编制索引的人员

简而言之,将您的模型更改为:

/@索引//不再需要
@spatical(spatialMode=spatialMode.HASH,name=“location”)//为空间字段命名
@实体
@表(name=“address”)
地址{
//加上这个
@ManyToMany(mappedBy=“addressSet”)
@包含
private Set personSet=new HashSet();
@场
@基本的
@列(name=“state”)
私有字符串状态;
@场
@基本的
@列(name=“town\u city”)
私人城市;
//@字段//这不是必需的
@经度
@基本的
@列(name=“x_coord”)
私人双xCoord;
//@字段//这不是必需的
@纬度
@基本的
@列(name=“y_coord”)
私人双yCoord;
}
@索引
@实体
@表(name=“person”)
人{
@场
@列(name=“weight”)
私人双倍重量;
@列(name=“age”)
私人整数年龄;
@org.hibernate.annotations.Cache(用法=
org.hibernate.annotations.cacheconcurrencystategy.READ\u WRITE)
@许多
@级联({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
@JoinTable(name=“person\u address”,
joinColumns={@JoinColumn(name=“person_id”)},
inverseJoinColumns={@JoinColumn(name=“address\u id”)})
@IndexedEmbedded//添加此
private Set addressSet=new HashSet();
@短暂的
@IndexedEmbedded//还添加了以下内容
公共地址getCurrentAddress(){
//这在您的模式中丢失了,我想是一个从addressSet中选择当前地址的getter?
}
}
然后重新编制索引。您的
Person
文档现在将有两个新字段:
addressSet.location
currentAddress.location

然后按如下方式编写查询:

FullTextSession FullTextSession=Search.getFullTextSession(entityManagerFactory.unwrap(SessionFactory.class).openSession());
this.queryBuilder=fullTextSession.getSearchFactory()
.buildQueryBuilder().forEntity(Person.class)
.overridesForField(“标识符.标识符\u边缘”,“标识符\u查询\u分析器”)
.get();
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());
    }