at.newmedialab.lmf.search.services.indexing.SolrCoreRuntime.java Source code

Java tutorial

Introduction

Here is the source code for at.newmedialab.lmf.search.services.indexing.SolrCoreRuntime.java

Source

/**
 * Copyright (C) 2013 Salzburg Research.
 *
 * 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 at.newmedialab.lmf.search.services.indexing;

import at.newmedialab.lmf.search.api.indexing.SolrIndexingService;
import at.newmedialab.lmf.search.filters.LMFSearchFilter;
import at.newmedialab.lmf.search.services.cores.SolrCoreConfiguration;
import at.newmedialab.lmf.worker.services.WorkerRuntime;
import org.apache.marmotta.kiwi.model.rdf.KiWiResource;
import org.apache.marmotta.platform.core.util.CDIContext;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
import org.apache.solr.client.solrj.request.AbstractUpdateRequest.ACTION;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.openrdf.model.Resource;
import org.openrdf.model.URI;
import org.openrdf.model.ValueFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;

/**
 * A class bundling administrative information about a running SOLR core.
 * <p/>
 * Author: Sebastian Schaffert
 */
public final class SolrCoreRuntime extends WorkerRuntime<SolrCoreConfiguration> {

    private Logger log = LoggerFactory.getLogger(SolrCoreRuntime.class);

    /**
     * The connection to the SOLR server to be used when committing this core
     */
    private SolrServer server;

    // used to ensure that the servers are initialised only by one thread
    private final ReentrantLock serverLock;

    private SolrIndexingService parent;

    public SolrCoreRuntime(SolrCoreConfiguration configuration, SolrIndexingService parent) {
        super(configuration);

        this.parent = parent;

        serverLock = new ReentrantLock();

        LMFSearchFilter filter = CDIContext.getInstance(LMFSearchFilter.class);
        if (filter.getCores() == null) {
            log.warn("SOLR server not registered in this application, cannot index resources");
        } else {
            serverLock.lock();
            try {
                server = new EmbeddedSolrServer(filter.getCores(), config.getName());
                log.debug("({}) created embedded SolrServer", config.getName());
            } finally {
                serverLock.unlock();
            }
        }
    }

    @Override
    protected void execute(Resource resource) {
        parent.indexResource(resource, this);
    }

    /**
     * Ask the server to retrieve all documents that depend on the resource passed as argument; this
     * query is
     * carried out by querying the dependencies field of a document.
     * 
     * @param resource
     * @return
     */
    public Collection<URI> listDependent(ValueFactory valueFactory, URI resource) {
        SolrQuery query = new SolrQuery();
        query.setQuery("lmf.dependencies:\"" + resource.stringValue() + "\"");
        query.setFields("lmf.uri");
        query.setRows(Integer.MAX_VALUE);
        try {
            SolrDocumentList docs = server.query(query).getResults();

            Set<URI> result = new HashSet<URI>();
            for (SolrDocument doc : docs) {
                result.add(valueFactory.createURI((String) doc.getFirstValue("lmf.uri")));
            }
            return result;
        } catch (SolrServerException e) {
            return Collections.emptyList();
        }
    }

    /**
     * Queue the input document in the document queue of this SolrCoreRuntime and check whether it is
     * necessary to commit.
     * 
     * @param doc the document to be added to the Solr Core
     */
    public void queueInputDocument(SolrInputDocument doc) {
        if (doc != null) {
            serverLock.lock();
            try {
                final Object fv = doc.getFieldValue("id");
                if (fv != null) {
                    UpdateRequest update = new UpdateRequest();
                    update.setCommitWithin(10000);
                    update.add(doc);
                    //update.setAction(ACTION.COMMIT, false, false);
                    server.request(update);
                } else {
                    log.warn("({}) rejected document without 'id' for update", config.getName());
                }
            } catch (IOException e) {
                log.warn("I/O exception while adding SOLR document to index", e);
            } catch (SolrServerException e) {
                log.warn("server exception while adding SOLR document to index", e);
            } finally {
                serverLock.unlock();
            }
        }
    }

    /**
     * Queue the deletion of a document in the Solr Core and check whether it is necessary to
     * commit.
     * 
     * @param docId
     */
    public void queueDeletion(String docId) {
        serverLock.lock();
        try {
            UpdateRequest update = new UpdateRequest();
            update.setCommitWithin(10000);
            update.deleteById(docId);
            //update.setAction(ACTION.COMMIT, false, false);
            server.request(update);
        } catch (IOException e) {
            log.warn("I/O exception while removing SOLR document from index", e);
        } catch (SolrServerException e) {
            log.warn("server exception while removing SOLR document from index", e);
        } finally {
            serverLock.unlock();
        }

    }

    /**
     * Force a commit of the solr index managed by this runtime. Used e.g. in testing to ensure the data is commited
     * and available for searching.
     */
    public void commit() {
        serverLock.lock();
        try {
            server.commit();
        } catch (IOException e) {
            log.warn("I/O exception while removing SOLR document from index", e);
        } catch (SolrServerException e) {
            log.warn("server exception while removing SOLR document from index", e);
        } finally {
            serverLock.unlock();
        }
    }

    /**
     * Clear the index managed by this SolrCoreRuntime.
     */
    public void clear() {
        serverLock.lock();
        try {
            UpdateRequest request = new UpdateRequest();
            request.deleteByQuery("id:[* TO *]");
            request.setAction(ACTION.COMMIT, true, true);

            server.request(request);
        } catch (IOException e) {
            log.error("(" + config.getName() + ") could not clear search index: an I/O Exception occurred", e);
        } catch (SolrServerException e) {
            log.error(
                    "(" + config.getName()
                            + ") could not clear search index: a SOLR Exception occurred (server not available?)",
                    e);
        } catch (Exception e) {
            log.error("(" + config.getName()
                    + ") index could not be cleared: a runtime Exception occurred (server sending invalid response?)",
                    e);
        } finally {
            serverLock.unlock();
        }

    }

    /**
     * Shutdown the core and all associated threads and connections
     */
    public void shutdown() {
        super.shutdown();
    }

    @Override
    public boolean schedule(Resource resource) {
        if (!super.schedule(resource)) {
            queueDeletion(getResourceId(resource));
            return false;
        } else {
            return true;
        }
    }

    private static String getResourceId(Resource r) {
        if (r instanceof KiWiResource)
            return String.valueOf(((KiWiResource) r).getId());
        else
            return r.stringValue();
    }

}