我目前正在尝试在JHipster微服务中实现多租户,但是我找不到一种方法来实现基于租户的ElasticSearch路由。
到目前为止,我已经成功地实现了PostgreSQL DB的数据源路由,类似于以下文章:https://websparrow.org/spring/spring-boot-dynamic-datasource-routing-using-abstractroutingdatasource
当我开始寻找在ElasticSearch中实现多租户的方法时,我发现了下面的文章:https://techblog.bozho.net/elasticsearch-multitenancy-with-routing/
在那里我读到了关于基于租户的路由。首先我试着在互联网上查找它,但我找到的任何东西都是5年前的,或者与java无关,更不用说与Spring/Jhipster了。然后我试着查看ElasticSearchTemplate的方法,@Document和@Settings的注解变量以及. yml文件中的配置选项,但没有找到任何有用的东西。
我现在使用的是Jhipster 7.9.3版,它使用的是Spring-Boot 2.7.3版,所有的微服务都是用JDL创建的,其中一半我在配置中加入了elasticsearch,另一半无所谓。
编辑:我想补充的是,我的数据库中的多租户是通过数据库分离归档的(Tenant1使用DB1,Tenant2使用DB2等),租户变量是一个枚举,不包含在我的实体中。
Edit2:我实现了我自己的解决方案。我使用租户作为索引,并使用DataSource Routing中的ContextHolder路由到正确的租户索引。为此,我必须对包". www.example.com"的生成类中的elasticsearchTemplate做一些更改。 <my.package.name>. repository.search ".
这可能不是使用ElasticSearch实现多租户的最有效方法,但它不需要太多配置。
下面是代码:
public interface ProductSearchRepository extends ElasticsearchRepository<Product, Long>, ProductSearchRepositoryInternal {}
interface ProductSearchRepositoryInternal {
Stream<Product> search(String query);
Stream<Product> search(Query query);
void index(Product entity);
}
class ProductSearchRepositoryInternalImpl implements ProductSearchRepositoryInternal {
private final ElasticsearchRestTemplate elasticsearchTemplate;
private final ProductRepository repository;
ProductSearchRepositoryInternalImpl(ElasticsearchRestTemplate elasticsearchTemplate, ProductRepository repository) {
this.elasticsearchTemplate = elasticsearchTemplate;
this.repository = repository;
}
@Override
public Stream<Product> search(String query) {
NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(queryStringQuery(query));
return search(nativeSearchQuery);
}
@Override
public Stream<Product> search(Query query) {
return elasticsearchTemplate.search(query, Product.class, IndexCoordinates.of(TenantContextHolder.getTenantContext().getTenant())).map(SearchHit::getContent).stream();
}
@Override
public void index(Product entity) {
repository.findById(entity.getId()).ifPresent(t -> elasticsearchTemplate.save(t, IndexCoordinates.of(TenantContextHolder.getTenantContext().getTenant())));
}
}
编辑3:由于人们可能不知道. getTenant()来自哪里,我将展示我的租户枚举:
public enum Tenant {
TENANTA("tenant_a"),
TENANTB("tenant_b");
String tenant;
Tenant(String name) {
this.tenant=name;
}
public String getTenant() {
return this.tenant;
}
}
Edit4:我的解决方案没有按计划工作,一旦我找到更好更健壮的解决方案,我会给出更新。
Edit5:我已经找到了如何实现基于租户的路由。首先,你必须添加以下注解到你的实体:
@org.springframework.data.elasticsearch.annotations.Routing(value = "tenant")
在我的例子中,我必须将枚举"Tenant"与getter和setter一起包含到实体中:
@Transient
private Tenant tenant;
public Tenant getTenant() {
return tenant;
}
public void setTenant(Tenant tenant) {
this.tenant = tenant;
}
然后,我必须在处理REST请求期间设置租户,然后才能由elasticsearchtemplate索引:
entity.setTenant(TenantContextHolder.getTenantContext());
至于搜索功能,我必须添加一个术语查询作为过滤器来启用路由:
@Override
public Stream<Product> search(String query) {
NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(queryStringQuery(query)
, QueryBuilders.termQuery("_routing", TenantContextHolder.getTenantContext()));
return search(nativeSearchQuery);
}
"nativeSearchQuery"的方法"setRoute(String route)"要么在我的情况下不起作用,要么我不明白它是如何工作的。
我已经成功地用GET和POST请求测试了这个实现。目前我遇到了一个问题,如果来自一个租户的实体的id与来自另一个租户的实体的id相同,则elasticsearch覆盖数据。
1条答案
按热度按时间daolsyd01#
经过反复试验,我找到了覆盖问题的解决方案,成功地完成并测试了基于租户的路由实现。
Product.java
产品搜索存储库