org.opensextant.util.SolrProxy.java Source code

Java tutorial

Introduction

Here is the source code for org.opensextant.util.SolrProxy.java

Source

/**
 * Copyright 2012-2013 The MITRE Corporation.
 *
 * 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.
 *
 *
 * **************************************************************************
 * NOTICE This software was produced for the U. S. Government under Contract No.
 * W15P7T-12-C-F600, and is subject to the Rights in Noncommercial Computer
 * Software and Noncommercial Computer Software Documentation Clause
 * 252.227-7014 (JUN 1995)
 *
 * (c) 2012 The MITRE Corporation. All Rights Reserved.
 * **************************************************************************
 *
 */
package org.opensextant.util;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.apache.solr.client.solrj.SolrRequest;
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.impl.HttpSolrServer;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.core.CoreContainer;
import org.opensextant.ConfigException;
import org.opensextant.data.Place;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * As Xponents is a multi-core instance of Solr, a single default solr home and default solr core
 * does not make sense.  Each wrapper around Solr (via SolrProxy) needs to name the solr home and an explicit core name.
 *
 * @author ubaldino
 */
public class SolrProxy extends SolrUtil {

    /**A single method to help find a suitable value for SOLR HOME
     *
     * If given is null, then system variables are checked.
     * @param given solr home.
     */
    public static String deriveSolrHome(String given) throws ConfigException {
        if (given != null) {
            return given;
        }

        String solrHome = System.getProperty("opensextant.solr");
        if (solrHome != null) {
            return solrHome;
        }
        solrHome = System.getProperty("solr.solr.home");

        if (solrHome != null) {
            return solrHome;
        }

        solrHome = System.getProperty("solr.url");
        if (solrHome != null) {
            return solrHome;
        }

        throw new ConfigException(
                "A non-null value for SOLR HOME is required; Either pass to constructor, set opensextant.solr, set solr.solr.home, or solr.url");

    }

    protected String solrHome = null;
    protected String coreName = null;

    /**
     * Initializes a Solr server from a URL
     *
     * @throws IOException err
     */
    public SolrProxy(URL url) throws IOException {
        this.server_url = url;
        solrServer = initializeHTTP(this.server_url);
    }

    /**
     * Initializes a Solr server from the SOLR_HOME environment variable.
     *
     * @param core  name of solr core
     * @throws ConfigException cfg err
     */
    public SolrProxy(String core) throws ConfigException {
        this.server_url = null;
        this.solrHome = deriveSolrHome(null);
        this.coreName = core;
        solrServer = setupCore(solrHome, core);
    }

    /**
     * Initializes a Solr server from the SOLR_HOME environment variable.
     *
     * @param solr_home the solr_home
     * @param core  name of solr core
     * @throws ConfigException cfg err
     */
    public SolrProxy(String solr_home, String core) throws ConfigException {
        this.server_url = null;
        solrHome = solr_home;
        this.coreName = core;
        solrServer = setupCore(solrHome, core);
    }

    protected Logger logger = LoggerFactory.getLogger(SolrProxy.class);
    protected SolrServer solrServer = null;
    private UpdateRequest solrUpdate = null;
    protected URL server_url = null;
    private boolean writable = false;

    public void setWritable(boolean b) {
        writable = b;
    }

    /**
     *
     * Is Solr server instance allowed to write to index?
     * @return true if index is intended to be writable.
     */
    public boolean isWritable() {
        return writable;
    }

    /**
     * Get an HTTP server for Solr.
     *
     * @param url server represented by URL
     * @return Instance of a Solr server
     * @throws MalformedURLException
     */
    public static SolrServer initializeHTTP(URL url) throws MalformedURLException {

        HttpSolrServer server = new HttpSolrServer(url.toString());
        server.setAllowCompression(true);

        return server;

    }

    /**
     * Creates an EmbeddedSolrServer given solr home & the core to use.
     * These may be null and you get the default.
     *
     * @param _solrHome  solr home
     * @param _coreName  name of core
     * @return the embedded solr server
     * @throws ConfigException on err
     */
    public static EmbeddedSolrServer setupCore(String _solrHome, String _coreName) throws ConfigException {

        try {
            CoreContainer solrContainer;

            if (_solrHome == null) {
                solrContainer = new CoreContainer();
            } else {
                solrContainer = new CoreContainer(_solrHome);
            }
            solrContainer.load();// since Solr 4.4

            return new EmbeddedSolrServer(solrContainer, _coreName);

        } catch (Exception err) {
            throw new ConfigException("Failed to set up Embedded Solr at " + _solrHome + " CORE:" + _coreName, err);
        }
    }

    /**
     * Creates the bare minimum Gazetteer Place record
     * @param gazEntry a solr document of key/value pairs
     * @return Place obj
     */
    public static Place createPlace(SolrDocument gazEntry) {

        Place bean = new Place(SolrUtil.getString(gazEntry, "place_id"), SolrProxy.getString(gazEntry, "name"));
        populatePlace(gazEntry, bean);
        return bean;
    }

    /**
     * Populate the data card.
     * @param gazEntry solr doc
     * @param bean place obj to populate
     */
    public static void populatePlace(SolrDocument gazEntry, Place bean) {
        String nt = SolrUtil.getString(gazEntry, "name_type");
        if (nt != null) {
            if ("code".equals(nt)) {
                bean.setName_type('A');
            } else {
                bean.setName_type(nt.charAt(0));
            }
        }

        bean.setCountryCode(SolrUtil.getString(gazEntry, "cc"));

        // Other metadata.
        bean.setAdmin1(SolrUtil.getString(gazEntry, "adm1"));
        bean.setAdmin2(SolrUtil.getString(gazEntry, "adm2"));
        bean.setFeatureClass(SolrUtil.getString(gazEntry, "feat_class"));
        bean.setFeatureCode(SolrUtil.getString(gazEntry, "feat_code"));

        // Geo field is specifically Spatial4J lat,lon format.
        // Value should have already been validated as it was stored in index
        double[] xy = SolrUtil.getCoordinate(gazEntry, "geo");
        bean.setLatitude(xy[0]);
        bean.setLongitude(xy[1]);

        bean.setName_bias(SolrUtil.getDouble(gazEntry, "name_bias"));
        bean.setId_bias(SolrUtil.getDouble(gazEntry, "id_bias"));
    }

    /**
     * Search an OpenSextant solr gazetteer.
     *
     * @param index solr server handle
     * @param qparams search parameters
     * @return list of places
     * @throws SolrServerException on err
     */
    public static List<Place> searchGazetteer(SolrServer index, SolrParams qparams) throws SolrServerException {

        QueryResponse response = index.query(qparams, SolrRequest.METHOD.GET);

        List<Place> places = new ArrayList<>();
        SolrDocumentList docList = response.getResults();

        for (SolrDocument solrDoc : docList) {
            places.add(SolrProxy.createPlace(solrDoc));
        }

        return places;
    }

    /**
     * Add one solr record.
     *
     * @param solrRecord document/gazetteer or other entry to add to index
     * @throws Exception on err ???
     */
    public void add(SolrInputDocument solrRecord) throws Exception {

        if (!this.writable) {
            throw new Exception("This instance is not configured for writing to index");
        }

        // Initialize per batch if nec.y
        if (solrUpdate == null) {
            solrUpdate = new UpdateRequest();
        }

        // Initialize per record
        // .. add data to record
        // .. add record to batch request
        solrUpdate.add(solrRecord);
    }

    /**
     * Add many solr records.
     *
     * @param solrRecords array of records to add
     * @throws Exception on err
     */
    public void add(java.util.Collection<SolrInputDocument> solrRecords) throws Exception {

        if (!this.writable) {
            throw new Exception("This instance is not configured for writing to index");
        }

        // Initialize per batch if nec.y
        if (solrUpdate == null) {
            solrUpdate = new UpdateRequest();
        }

        // Initialize per record
        // .. add data to record
        // .. add record to batch request
        solrUpdate.add(solrRecords);
    }

    /**
     *  Reopen an existing solr proxy.
     *
     * @throws ConfigException the config exception
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public void openIndex() throws ConfigException, IOException {
        if (solrServer == null) {
            if (server_url != null) {
                solrServer = initializeHTTP(server_url);
            } else {
                solrServer = setupCore(solrHome, coreName);
            }
        }
    }

    /**
     * Optimizes the Solr server.
     *
     * @throws IOException on err
     * @throws SolrServerException the solr server exception
     */
    public void optimize() throws IOException, SolrServerException {
        solrServer.optimize(true, false); // Don't wait'
    }

    /**
     * Invokes <code>saveIndex(false)</code>
     */
    public void saveIndex() {
        saveIndex(false);
    }

    /**
     * Save and optionally records to server or index On failure, current
     * accumulating request is cleared and nullified to avoid retransmitting bad
     * data.
     * 
     * In the event of a failure all records since last "saveIndex" would be
     * lost and should be resubmitted.
     *
     * @param commit  true, if we should commit updates
     */
    public void saveIndex(boolean commit) {
        if (solrUpdate == null) {
            return;
        }

        logger.info("Saving records to index");
        try {
            solrServer.request(solrUpdate);
            if (commit) {
                solrServer.commit();
            }
            solrUpdate.clear();
            solrUpdate = null;
        } catch (Exception filex) {
            logger.error("Index failed during indexing", filex);
            solrUpdate.clear();
            solrUpdate = null;
        }
    }

    /**
     * Save and reopen.
     *
     * @throws ConfigException the config exception
     * @throws IOException on err
     */
    public void saveAndReopen() throws ConfigException, IOException {
        saveIndex(/* commit = */true);
        openIndex();
    }

    /**
     *
     */
    public void close() {
        if (isWritable()) {
            saveIndex();
        }

        if (solrServer != null) {
            solrServer.shutdown();
            solrServer = null;
        }
    }

    public SolrServer getInternalSolrServer() {
        return solrServer;
    }

}