2

I am working with an application that aggregates data from multiple sources. In this case I need to connect to two different Solr services with unrelated data. To this end I set up two different data repositories. I have defined the beans as follows:

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

The problem I have is that I cannot figure out how to have two completely independent Solr clients, with each pointing at different urls. As the beans solrClient() and solrTemplate() are needed, and trying to create a new Context with different URLs simply gets the solrClient and solrTemplate bean overwritten with the beans created first. Each client works fine if they are the only Solr clients defined.

In short, how can I create two (or more) different Spring Solr clients, each connecting to different URLS?

Additional Information is response to comments...

I have attempted to simply recreate the SolrContext class with different configurations.Consider the following:

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

What happens here is that the @Bean's solrClient, and solrTemplate get overridden when the beans are created during startup.

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]

Testing shows that the URL is indeed only the first bean instantiated. I have also tried renaming the second context beans to something else, but then the Solr functionality can't locate/identify the beans.

Here is the error thrown when trying to define more than one 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

In short it appears that only one URL is possible for the Spring Solr Data library. (note: using version 2.1.4) Does anyone have more than one URL (not just core) working under Spring Solr data?

Bill
  • 2,623
  • 1
  • 27
  • 41

2 Answers2

5

Since there are multiple beans of the same type within the same Spring context, disambiguation is required when using autowiring. The following should work:

Configuration for first Solr server

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

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

Configuration for second Solr server

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

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

Using the SolrTemplates

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

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

This works because:

  1. The first SolrTemplate refers to its SolrClient directly through an unambiguous method call (primarySolrClient()).
  2. The second SolrTemplate refers to its SolrClient directly through an unambiguous method call (secondarySolrClient()).
  3. The first SolrTemplate is unambiguously named (@Bean("primary")).
  4. The second SolrTemplate is also unambiguously named (@Bean("secondary")).
  5. The SolrTemplates are injected unambiguously using their unique names through @Qualifier.

More SolrTemplates can be initialized and injected in this fashion.

A sample project is available on Github demonstrating this.

manish
  • 19,695
  • 5
  • 67
  • 91
0

create another bean for spring to use solr, this is easy and clean :

@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);
    }
}
jeorfevre
  • 2,286
  • 1
  • 17
  • 27
  • I have done this. It does not work, as the beans get overridden by the first instance. What I need is to point to a different SERVER, not core. Here is from the startup logs "Overriding bean definition for bean 'solrClient' with a different definition: replacing ..." There is a similar message for the solrTemplate bean. – Bill Jun 08 '17 at 15:17
  • it's overridden by Spring? – jeorfevre Jun 08 '17 at 15:26
  • yes. See additional comments added to the question. – Bill Jun 08 '17 at 17:30