繁体   English   中英

如何使用 Hibernate Search 以单向多对多和多对一关系连接数据

[英]How to join data in unidirectional ManyToMany and ManyToOne relation with Hibernate Search

我是 Hibernate Search 的新手,我正在使用 Hibernate Search 6.1.4.Final以及 Spring Boot 2.6.7 、 Spring Data JPA 2.6.7和 PostgreSQL 14 我有以下架构:

CREATE TABLE manufacturer
(
    id         UUID,
    PRIMARY KEY (id)
);

CREATE TABLE flavor
(
    id         UUID,
    PRIMARY KEY (id)
);

CREATE TABLE tobacco
(
    id              UUID,
    name            VARCHAR   NOT NULL,
    manufacturer_id UUID      NOT NULL,
    PRIMARY KEY (id)
);

ALTER TABLE tobacco
    ADD CONSTRAINT fk_manufacturer FOREIGN KEY (manufacturer_id) REFERENCES manufacturer (id);

CREATE TABLE tobacco_flavor
(
    tobacco_id UUID REFERENCES tobacco (id) ON UPDATE CASCADE ON DELETE CASCADE,
    flavor_id  UUID REFERENCES flavor (id) ON UPDATE CASCADE,
    CONSTRAINT tobacco_flavor_pk PRIMARY KEY (tobacco_id, flavor_id)
);

我在烟草和制造商之间有一个单向多对一关系,在烟草和风味之间有另一个单向多对多关系。 索引实体是:

@Data
@Entity
@Indexed
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
@EqualsAndHashCode(of = "id")
@EntityListeners(AuditingEntityListener.class)
public class Tobacco {
    @Id
    @GeneratedValue
    private UUID id;
    @NotBlank
    @FullTextField(analyzer = "name")
    @FullTextField(name = "name_prefix", analyzer = "name_prefix", searchAnalyzer = "name")
    private String name;
    @ManyToOne(fetch = FetchType.EAGER) // this is EAGER because hibernate cannot serialize the proxy wrapper when using LAZY
    @JoinColumn(name = "manufacturer_id", nullable = false)
    private Manufacturer manufacturer;
    @ManyToMany(cascade = {
        CascadeType.MERGE
    })
    @JoinTable(name = "tobacco_flavor",
        joinColumns = @JoinColumn(name = "tobacco_id", referencedColumnName = "id"),
        inverseJoinColumns = @JoinColumn(name = "flavor_id", referencedColumnName = "id")
    )
    private Set<Flavor> flavors;
}

我正在使用以下 lucene 配置器:

@Component("luceneTobaccoAnalysisConfigurer")
public class LuceneTobaccoAnalysisConfigurer implements LuceneAnalysisConfigurer {
    @Override
    public void configure(LuceneAnalysisConfigurationContext context) {
        context.analyzer("name").custom()
            .tokenizer("standard")
            .tokenFilter("lowercase")
            .tokenFilter("asciiFolding");

        context.analyzer("name_prefix").custom()
            .tokenizer("standard")
            .tokenFilter("lowercase")
            .tokenFilter("asciiFolding")
            .tokenFilter("edgeNGram")
            .param("minGramSize", "2")
            .param("maxGramSize", "7");
    }
}

我正在执行以下查询:

public List<Tobacco> find(String query) {
    return Search.session(entityManager)
        .search(Tobacco.class)
        .where(f -> f.match()
            .fields("barcode", "name").boost(2.0f)
            .fields("name_prefix")
            .matching(query)
            .fuzzy()
        )
        .fetchHits(10);
}

当我执行查询时,Hibernate 使用连接执行 5 个 SELECT 查询而不是 1 个。 我想始终按烟草名称查询并检索与其关联的所有实体(口味和制造商),有没有什么方法可以指示 Hibernate Search 有效地通过连接执行查询?

要控制 Hibernate Search 加载的内容,您可以在构建搜索查询时通过调用.loading( o -> o.graph( someGraph, GraphSemantic.FETCH ) ) 在 Hibernate Search 中利用 JPA 实体图

像这样的东西?

public List<Tobacco> find(String query) {
    EntityGraph<Tobacco> graph = entityManager.createEntityGraph( Tobacco.class ); 
    graph.addAttributeNodes( "manufacturer" );
    graph.addAttributeNodes( "flavors" );
    return Search.session(entityManager)
        .search(Tobacco.class)
        .where(f -> f.match()
            .fields("barcode", "name").boost(2.0f)
            .fields("name_prefix")
            .matching(query)
            .fuzzy()
        )
        .loading( o -> o.graph( graph, GraphSemantic.FETCH ) ) 
        .fetchHits(10);
}

但是,根据您的模型和实体图,这可能会导致执行多个查询(由于 Hibernate ORM 中的实现限制)。 在这种情况下,您可以探索这些会影响任何加载的替代解决方案,而不仅仅是在 Hibernate Search 中加载:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM