Problem
In our product, user is able to create additional core: Solr will update solr.xml to add extra core information. But at some time, we need update solr.xml to add our extra cores.
This is a common requirement: we need upgrade solr config files in future release, but at same time keep customer's change.
For solrconfig.xml or solrschema.xml, we can use xi:include to put our change in one xml(for example solrconfig-upgrade.xml), user should only change solrconfig.xml either manually or via GUI.
Please refer to http://wiki.apache.org/solr/SolrConfigXml#XInclude
But this doesn't work for solr.xml, as if we define xi:include in solr.xml:
later if user creates another solr core, solr will update solr.xml: it will delete <xi:include> and overwrite cores section to include all cores.
Solution
We can define extra cores in a property file: cvanalytics_solr_extra.propertie like below:
In our product, user is able to create additional core: Solr will update solr.xml to add extra core information. But at some time, we need update solr.xml to add our extra cores.
This is a common requirement: we need upgrade solr config files in future release, but at same time keep customer's change.
For solrconfig.xml or solrschema.xml, we can use xi:include to put our change in one xml(for example solrconfig-upgrade.xml), user should only change solrconfig.xml either manually or via GUI.
Please refer to http://wiki.apache.org/solr/SolrConfigXml#XInclude
But this doesn't work for solr.xml, as if we define xi:include in solr.xml:
<solr persistent="true" sharedLib="lib" shareSchema="true"> <cores adminPath="/admin/cores" defaultCoreName="collection1"
host="${host:}" hostPort="${jetty.port:}" hostContext="${hostContext:}" zkClientTimeout="${zkClientTimeout:15000}"><core name="collection1" instanceDir="collection1"/> <!-- this doesn't work --> <xi:include href="solr_extracores.xml"/> </cores> </solr>
later if user creates another solr core, solr will update solr.xml: it will delete <xi:include> and overwrite cores section to include all cores.
Solution
We can define extra cores in a property file: cvanalytics_solr_extra.propertie like below:
# support corename_name, corename_instanceDir, corename_schemaName, corename_configName extra_cores=extracore1, extracore2 extracore1_name=extracore1 extracore1_instanceDir=extracore1 extracore1_schemaName=extracore1_schema.xml extracore1_configName=extracore1_config.xml ....We will iterate all core names in extra_cores, if it's already loaded: CoreContainer.getCoreFromAnyList(core_name) returns not null, we ignore, Otherwise, we create a SolrCore and register it.
Implementation Code
org.apache.solr.core.CoreContainer.Initializer
private void initExtraCores(CoreContainer cores) throws RuntimeException {
try {
Properties cvProps = cores.getCVProperties();
String solrxml_extra = cvProps.getProperty("solrxml_extra");
if (!StringUtils.isBlank(solrxml_extra)) {
File solrxml_extraFile = new File(cores.getSolrHome(), solrxml_extra);
Properties solrxml_extraProps = readProperties(solrxml_extraFile);
String extra_cores = solrxml_extraProps.getProperty("extra_cores");
if (!StringUtils.isBlank(extra_cores)) {
String[] extra_coresArr = extra_cores.split(",");
for (String extra_core : extra_coresArr) {
extra_core = extra_core.trim();
if (cores.getCoreFromAnyList(extra_core) == null) {
String coreName = solrxml_extraProps.getProperty(extra_core
+ "_name");
if (StringUtils.isBlank(coreName)) {
coreName = extra_core;
}
String instanceDir = solrxml_extraProps.getProperty(extra_core
+ "_instanceDir");
if (StringUtils.isBlank(instanceDir)) {
throw new RuntimeException("No instanceDir defined for "
+ coreName + "in " + solrxml_extraFile);
}
CoreDescriptor cd = new CoreDescriptor(cores, coreName,
instanceDir);
String schemaName = solrxml_extraProps.getProperty(extra_core
+ "_schemaName");
if (!StringUtils.isBlank(schemaName)) {
cd.setSchemaName(schemaName);
}
String configName = solrxml_extraProps.getProperty(extra_core
+ "_configName");
if (!StringUtils.isBlank(configName)) {
cd.setConfigName(configName);
}
SolrCore core = cores.create(cd);
cores.register(core, false);
}
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public CoreContainer initialize() {
CoreContainer cores = null;
String solrHome = SolrResourceLoader.locateSolrHome();
cores = new CoreContainer(solrHome);
if (fconf.exists()) {
cores.load(solrHome, fconf);
} else {
log.info("no solr.xml file found - using default");
try {
cores.load(solrHome, new InputSource(new ByteArrayInputStream(DEF_SOLR_XML.getBytes("UTF-8"))));
} catch (Exception e) {
throw new SolrException(ErrorCode.SERVER_ERROR,
"CoreContainer.Initialize failed when trying to load default solr.xml file", e);
}
cores.configFile = fconf;
}
// call initExtraCores
initExtraCores(cores);
return cores;
}