[英]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 中加载:
flavors
关联上使用@Fetch(FetchMode.JOIN)
。batch_fetch_size
配置属性和@BatchSize
注释。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.