Spring Solr - 将多个客户端用于不同的服务

Posted

技术标签:

【中文标题】Spring Solr - 将多个客户端用于不同的服务【英文标题】:Spring Solr - Using multiple clients to different services 【发布时间】:2017-06-07 22:18:22 【问题描述】:

我正在使用一个聚合来自多个来源的数据的应用程序。在这种情况下,我需要使用不相关的数据连接到两个不同的 Solr 服务。为此,我建立了两个不同的数据存储库。我将 bean 定义如下:

@Configuration
@EnableSolrRepositories(basePackages="foo.utilities.solr.repos.gcr", multicoreSupport=true)
public class GcrSolrContext 

    @Bean
    public SolrClient solrClient() 
        return new HttpSolrClient("http://foo:8086/solr/gcr");
    

    @Bean
    public SolrTemplate solrTemplate(SolrClient client) throws Exception 
        return new SolrTemplate(client);
    

我的问题是我无法弄清楚如何拥有两个完全独立的 Solr 客户端,每个客户端都指向不同的 url。由于需要 solrClient() 和 solrTemplate() bean,并且尝试使用不同的 URL 创建新的 Context 只会让 solrClient 和 solrTemplate bean 被首先创建的 bean 覆盖。如果它们是唯一定义的 Solr 客户端,则每个客户端都可以正常工作。

简而言之,我如何创建两个(或更多)不同的 Spring Solr 客户端,每个客户端都连接到不同的 URL?

附加信息是对 cme​​ts 的响应...

我试图简单地重新创建具有不同配置的 SolrContext 类。请考虑以下几点:

@Configuration
@EnableSolrRepositories(basePackages="foo.utilities.solr.repos.different", multicoreSupport=true)
public class DifferentSolrContext 

    @Bean
    public SolrClient solrClient() 
        return new HttpSolrClient("http://SomethingDifferent:8086/solr/something");
    

    @Bean
    public SolrTemplate solrTemplate(SolrClient client) throws Exception 
        return new SolrTemplate(client);
    

这里发生的是@Bean 的 solrClient 和 solrTemplate 在启动期间创建 bean 时被覆盖。

INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Overriding bean definition for bean 'solrClient' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=yyySolrContext; factoryMethodName=solrClient; initMethodName=null; destroyMethodName=(inferred); defined in foo.utilities.solr.GcrSolrContext] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=xxxSolrContext; factoryMethodName=solrClient; initMethodName=null; destroyMethodName=(inferred); defined in foo.utilities.solr.XxxSolrContext]
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Overriding bean definition for bean 'solrTemplate' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=yyySolrContext; factoryMethodName=solrTemplate; initMethodName=null; destroyMethodName=(inferred); defined in foo.utilities.solr.GcrSolrContext] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=haystackSolrContext; factoryMethodName=solrTemplate; initMethodName=null; destroyMethodName=(inferred); defined in foo.utilities.solr.XxxSolrContext]

测试表明 URL 确实只是第一个实例化的 bean。我还尝试将第二个上下文 bean 重命名为其他内容,但是 Solr 功能无法定位/识别 bean。

这是尝试定义多个 SolrClient 时引发的错误。

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.apache.solr.client.solrj.SolrClient' available: expected single matching bean but found 2: solrClient2,solrClient

简而言之,Spring Solr 数据库似乎只能使用一个 URL。 (注意:使用版本 2.1.4)是否有人在 Spring Solr 数据下拥有多个 URL(不仅仅是核心)?

【问题讨论】:

【参考方案1】:

由于在同一个 Spring 上下文中有多个相同类型的 bean,因此在使用自动装配时需要消除歧义。以下应该有效:

第一个 Solr 服务器的配置

@Configuration
public class PrimarySolrContext 
  @Bean
  public SolrClient primarySolrClient() 
    return new HttpSolrClient(...);
  

  @Bean("primary")
  public SolrTemplate solrTemplate() 
    return new SolrTemplate(primarySolrClient());
  

第二个 Solr 服务器的配置

@Configuration
public class SecondarySolrContext 
  @Bean
  public SolrClient secondarySolrClient() 
    return new HttpSolrClient(...);
  

  @Bean("secondary")
  public SolrTemplate solrTemplate() 
    return new SolrTemplate(secondarySolrClient());
  

使用SolrTemplates

@Service
public class SearchService 
  @Autowired
  @Qualifier("primary")
  private SolrTemplate primarySolrTemplate;

  @Autowired
  @Qualifier("secondary")
  private SolrTemplate secondarySolrTemplate;

之所以有效,是因为:

    第一个 SolrTemplate 直接通过明确的方法调用 (primarySolrClient()) 引用其 SolrClient。 第二个SolrTemplate 直接通过明确的方法调用(secondarySolrClient()) 引用它的SolrClient。 第一个 SolrTemplate 被明确命名为 (@Bean("primary"))。 第二个SolrTemplate 也被明确命名为 (@Bean("secondary"))。 SolrTemplates 通过 @Qualifier 使用其唯一名称明确注入。

更多SolrTemplates 可以用这种方式初始化和注入。

on Github 提供了一个示例项目来证明这一点。

【讨论】:

它不起作用,错误是 - 一个组件需要一个名为 'solrClient' 的 bean,但无法找到。【参考方案2】:

为spring创建另一个bean来使用solr,这很简单:

@Configuration
@EnableSolrRepositories(basePackages="foo.utilities.solr.repos.xxx", multicoreSupport=true)
public class XXXSolrContext 

    @Bean
    public SolrClient getClient() 
        return new HttpSolrClient("http://foo:8086/solr/xxx");
    

    @Bean
    public SolrTemplate getTemplate(SolrClient client) throws Exception 
        return new SolrTemplate(client);
    

【讨论】:

我已经做到了。它不起作用,因为 bean 被第一个实例覆盖。我需要的是指向不同的服务器,而不是核心。这是来自启动日志“用不同的定义覆盖 bean 'solrClient' 的 bean 定义:替换 ...” solrTemplate bean 有类似的消息。 它被 Spring 覆盖了吗? 是的。查看添加到问题中的其他 cmets。

以上是关于Spring Solr - 将多个客户端用于不同的服务的主要内容,如果未能解决你的问题,请参考以下文章

使用spring-data-solr做solr客户端

Spring Data Solr - 由 OR 分隔的多个 FilterQueries

Solr和Spring Data Solr

Spring集成Solr 客户端,提示如下错误信息:java.lang.NoClassDefFoundError: org/apache/http/message/TokenParser

在solr中查询具有不同字段的多个集合

是否可以结合多个字段进行 Solr 分面,例如 RMDB 中多个列上的不同?