简体   繁体   English

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

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

I'm new to Hibernate Search, I'm using Hibernate Search 6.1.4.Final along with Spring Boot 2.6.7 , Spring Data JPA 2.6.7 and PostgreSQL 14 .我是 Hibernate Search 的新手,我正在使用 Hibernate Search 6.1.4.Final以及 Spring Boot 2.6.7 、 Spring Data JPA 2.6.7和 PostgreSQL 14 I have the following schema:我有以下架构:

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

I have an unidirectional ManyToOne relationship between Tobacco and Manufacturer, and another unidirectional ManyToMany relationship between Tobacco and Flavor.我在烟草和制造商之间有一个单向多对一关系,在烟草和风味之间有另一个单向多对多关系。 The indexed entity is:索引实体是:

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

I'm using the following lucene configurer:我正在使用以下 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");
    }
}

And I'm performing the following query:我正在执行以下查询:

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);
}

When I execute the query Hibernate performs 5 SELECT queries instead of 1 using joins.当我执行查询时,Hibernate 使用连接执行 5 个 SELECT 查询而不是 1 个。 I would like to query always by tobacco name and retrieve all of the entities associated to it (flavors and manufacturer), is there any way of instructing Hibernate Search to perform the query with a join efficiently?我想始终按烟草名称查询并检索与其关联的所有实体(口味和制造商),有没有什么方法可以指示 Hibernate Search 有效地通过连接执行查询?

To control what gets loaded by Hibernate Search, you can leverage JPA entity graphs in Hibernate Search by calling .loading( o -> o.graph( someGraph, GraphSemantic.FETCH ) ) when building your search query.要控制 Hibernate Search 加载的内容,您可以在构建搜索查询时通过调用.loading( o -> o.graph( someGraph, GraphSemantic.FETCH ) ) 在 Hibernate Search 中利用 JPA 实体图

Something like this?像这样的东西?

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);
}

However, depending on your model and entity graph, this might lead to more than one query being executed regardless (due to implementation constraints in Hibernate ORM).但是,根据您的模型和实体图,这可能会导致执行多个查询(由于 Hibernate ORM 中的实现限制)。 In that case, you can explore these alternative solutions that will affect any loading, not just loading in Hibernate Search:在这种情况下,您可以探索这些会影响任何加载的替代解决方案,而不仅仅是在 Hibernate Search 中加载:

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

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