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

问题描述 投票:0回答:1

我们有以下情况

给出以下两个实体

@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 = ...

elasticsearch lucene hibernate-search
1个回答
0
投票

基本上,您正在尝试实施联接操作。正如您所看到的,在客户端进行加入的技术难题并不容易解决。

© www.soinside.com 2019 - 2024. All rights reserved.