/**
* Copyright 2008 The University of North Carolina at Chapel Hill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package edu.unc.lib.dl.data.ingest.solr.indexing;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.ConcurrentUpdateSolrServer;
import org.apache.solr.client.solrj.util.ClientUtils;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.SolrInputField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import edu.unc.lib.dl.data.ingest.solr.exception.IndexingException;
import edu.unc.lib.dl.fedora.PID;
import edu.unc.lib.dl.search.solr.model.IndexDocumentBean;
import edu.unc.lib.dl.search.solr.service.SolrSearchService;
import edu.unc.lib.dl.search.solr.util.SolrSettings;
/**
* Performs batch add/delete/update operations to a Solr index.
*
* @author bbpennel
*
*/
public class SolrUpdateDriver {
private static final Logger log = LoggerFactory.getLogger(SolrUpdateDriver.class);
private SolrServer solrServer;
private SolrServer updateSolrServer;
private SolrSettings solrSettings;
@Autowired
private SolrSearchService searchService;
private int autoPushCount;
private int updateThreads;
private static String ID_FIELD = "id";
private static String UPDATE_TIMESTAMP = "timestamp";
public void init() {
log.debug("Instantiating concurrent udpate solr server for " + solrSettings.getUrl());
solrServer = new ConcurrentUpdateSolrServer(solrSettings.getUrl(), autoPushCount, updateThreads);
updateSolrServer = new ConcurrentUpdateSolrServer(solrSettings.getUrl(), autoPushCount, updateThreads);
}
public void addDocument(IndexDocumentBean idb) throws IndexingException {
try {
solrServer.addBean(idb);
} catch (IOException e) {
throw new IndexingException("Failed to add document to solr", e);
} catch (SolrServerException e) {
throw new IndexingException("Failed to add document to solr", e);
}
}
/**
* Perform a partial document update from a IndexDocumentBean. Null fields are considered to be unspecified and will
* not be changed, except for the update timestamp field which is always set.
*
* @param operation
* @param idb
* @throws IndexingException
*/
public void updateDocument(String operation, IndexDocumentBean idb) throws IndexingException {
try {
SolrInputDocument sid = updateSolrServer.getBinder().toSolrInputDocument(idb);
for (String fieldName : sid.getFieldNames()) {
if (!ID_FIELD.equals(fieldName)) {
SolrInputField inputField = sid.getField(fieldName);
// Adding in each non-null field value, except the timestamp field which gets cleared if not specified so
// that it always gets updated as part of a partial update
if (inputField != null && (inputField.getValue() != null || UPDATE_TIMESTAMP.equals(fieldName))) {
Map<String, Object> partialUpdate = new HashMap<String, Object>();
partialUpdate.put(operation, inputField.getValue());
sid.setField(fieldName, partialUpdate);
}
}
}
if (log.isDebugEnabled())
log.debug("Performing partial update:\n{}", ClientUtils.toXML(sid));
updateSolrServer.add(sid);
} catch (IOException e) {
throw new IndexingException("Failed to add document to solr", e);
} catch (SolrServerException e) {
throw new IndexingException("Failed to add document to solr", e);
}
}
public void delete(PID pid) throws IndexingException {
this.delete(pid.getPid());
}
public void delete(String pid) throws IndexingException {
try {
solrServer.deleteById(pid);
} catch (IOException e) {
throw new IndexingException("Failed to delete document from solr", e);
} catch (SolrServerException e) {
throw new IndexingException("Failed to delete document from solr", e);
}
}
public void deleteByQuery(String query) throws IndexingException {
try {
solrServer.deleteByQuery(query);
} catch (IOException e) {
throw new IndexingException("Failed to add document batch to solr", e);
} catch (SolrServerException e) {
throw new IndexingException("Failed to add document batch to solr", e);
}
}
/**
* Force a commit of the currently staged updates.
*/
public void commit() throws IndexingException {
try {
solrServer.commit();
updateSolrServer.commit();
} catch (SolrServerException e) {
throw new IndexingException("Failed to commit changes to solr", e);
} catch (IOException e) {
throw new IndexingException("Failed to commit changes to solr", e);
}
}
public int getAutoPushCount() {
return autoPushCount;
}
public void setAutoPushCount(int autoPushCount) {
this.autoPushCount = autoPushCount;
}
public int getUpdateThreads() {
return updateThreads;
}
public void setUpdateThreads(int updateThreads) {
this.updateThreads = updateThreads;
}
public void setSolrServer(SolrServer solrServer) {
this.solrServer = solrServer;
}
public void setUpdateSolrServer(SolrServer solrServer) {
this.updateSolrServer = solrServer;
}
public void setSolrSettings(SolrSettings solrSettings) {
this.solrSettings = solrSettings;
}
}