nl.knaw.huygens.timbuctoo.index.solr.SolrIndex.java Source code

Java tutorial

Introduction

Here is the source code for nl.knaw.huygens.timbuctoo.index.solr.SolrIndex.java

Source

package nl.knaw.huygens.timbuctoo.index.solr;

/*
 * #%L
 * Timbuctoo VRE
 * =======
 * Copyright (C) 2012 - 2015 Huygens ING
 * =======
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public 
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #L%
 */

import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import nl.knaw.huygens.facetedsearch.FacetedSearchException;
import nl.knaw.huygens.facetedsearch.FacetedSearchLibrary;
import nl.knaw.huygens.facetedsearch.model.FacetedSearchResult;
import nl.knaw.huygens.facetedsearch.model.NoSuchFieldInIndexException;
import nl.knaw.huygens.facetedsearch.model.parameters.FacetedSearchParameters;
import nl.knaw.huygens.facetedsearch.model.parameters.IndexDescription;
import nl.knaw.huygens.facetedsearch.model.parameters.SortDirection;
import nl.knaw.huygens.facetedsearch.model.parameters.SortParameter;
import nl.knaw.huygens.solr.AbstractSolrServer;
import nl.knaw.huygens.timbuctoo.index.Index;
import nl.knaw.huygens.timbuctoo.index.IndexException;
import nl.knaw.huygens.timbuctoo.index.RawSearchUnavailableException;
import nl.knaw.huygens.timbuctoo.model.DomainEntity;
import nl.knaw.huygens.timbuctoo.model.Entity;
import nl.knaw.huygens.timbuctoo.vre.SearchException;
import nl.knaw.huygens.timbuctoo.vre.SearchValidationException;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
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 java.io.IOException;
import java.util.List;
import java.util.Map;

public class SolrIndex implements Index {

    protected static final SolrQuery COUNT_QUERY;

    private final SolrInputDocumentCreator solrDocumentCreator;
    private final AbstractSolrServer solrServer;
    private final String name;
    private final FacetedSearchLibrary facetedSearchLibrary;
    private final IndexDescription indexDescription;
    private final String rawSearchField;

    static {
        COUNT_QUERY = new SolrQuery();
        COUNT_QUERY.setQuery("*:*");
        COUNT_QUERY.setRows(0);
    }

    public SolrIndex(String name, String rawSearchField, IndexDescription indexDescription,
            SolrInputDocumentCreator solrDocumentCreator, AbstractSolrServer solrServer,
            FacetedSearchLibrary facetedSearchLibrary) {
        this.name = name;
        this.indexDescription = indexDescription;
        this.solrDocumentCreator = solrDocumentCreator;
        this.solrServer = solrServer;
        this.facetedSearchLibrary = facetedSearchLibrary;
        this.rawSearchField = rawSearchField;
    }

    @Override
    public void add(List<? extends DomainEntity> variations) throws IndexException {
        updateIndex(variations);

    }

    private void updateIndex(List<? extends DomainEntity> variations) throws IndexException {
        if (variations == null || variations.isEmpty()) {
            return;
        }

        SolrInputDocument document = solrDocumentCreator.create(variations);

        try {
            solrServer.add(document);
        } catch (SolrServerException e) {
            throw new IndexException(e);
        } catch (IOException e) {
            throw new IndexException(e);
        }
    }

    @Override
    public void update(List<? extends DomainEntity> variations) throws IndexException {
        updateIndex(variations);
    }

    @Override
    public void deleteById(String id) throws IndexException {
        if (id == null) {
            return;
        }

        try {
            solrServer.deleteById(id);
        } catch (SolrServerException e) {
            throw new IndexException(e);
        } catch (IOException e) {
            throw new IndexException(e);
        }

    }

    @Override
    public void deleteById(List<String> ids) throws IndexException {
        try {
            if (ids != null && !ids.isEmpty()) {
                solrServer.deleteById(ids);
            }
        } catch (SolrServerException e) {
            throw new IndexException(e);
        } catch (IOException e) {
            throw new IndexException(e);
        }

    }

    @Override
    public void clear() throws IndexException {
        try {
            solrServer.deleteByQuery("*:*");
            solrServer.commit();
        } catch (SolrServerException e) {
            throw new IndexException(e);
        } catch (IOException e) {
            throw new IndexException(e);
        }
    }

    @Override
    public long getCount() throws IndexException {
        try {
            SolrDocumentList results = solrServer.search(COUNT_QUERY).getResults();
            return results.getNumFound();
        } catch (SolrServerException e) {
            throw new IndexException(e);
        }
    }

    @Override
    public void commit() throws IndexException {
        try {
            solrServer.commit();
        } catch (SolrServerException e) {
            throw new IndexException(e);
        } catch (IOException e) {
            throw new IndexException(e);
        }

    }

    @Override
    public void close() throws IndexException {
        try {
            this.commit();
        } finally {
            try {
                solrServer.shutdown();
            } catch (SolrServerException e) {
                throw new IndexException(e);
            } catch (IOException e) {
                throw new IndexException(e);
            }
        }
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public <T extends FacetedSearchParameters<T>> FacetedSearchResult search(
            FacetedSearchParameters<T> searchParameters) throws SearchException, SearchValidationException {
        try {
            List<String> facetFields = searchParameters.getFacetFields();
            if (facetFields == null || facetFields.isEmpty()) {
                searchParameters.setFacetFields(indexDescription.getFacetFields());
            }

            return facetedSearchLibrary.search(searchParameters);
        } catch (NoSuchFieldInIndexException e) {
            throw new SearchValidationException(e);
        } catch (FacetedSearchException e) {
            throw new SearchException(e);
        }
    }

    @Override
    public Iterable<Map<String, Object>> doRawSearch(String query, int start, int rows,
            Map<String, Object> additionalFilters) throws SearchException, RawSearchUnavailableException {
        QueryResponse queryResponse = null;
        String queryString = createSolrQuery(query, additionalFilters);
        SolrQuery solrQuery = new SolrQuery(queryString).setStart(start).setRows(rows);
        return getSingleRawResults(solrQuery);
    }

    private List<Map<String, Object>> getSingleRawResults(SolrQuery solrQuery) throws SearchException {
        QueryResponse queryResponse;
        try {
            queryResponse = solrServer.search(solrQuery);
        } catch (SolrServerException e) {
            throw new SearchException(e);
        }

        List<Map<String, Object>> results = Lists.newArrayList();
        for (SolrDocument doc : queryResponse.getResults()) {
            results.add(doc.getFieldValueMap());
        }
        return results;
    }

    private List<Map<String, Object>> getMultiRawResults(SolrQuery solrQuery) throws SearchException {
        QueryResponse queryResponse;
        try {
            queryResponse = solrServer.search(solrQuery);
        } catch (SolrServerException e) {
            throw new SearchException(e);
        }

        List<Map<String, Object>> results = Lists.newArrayList();
        for (SolrDocument doc : queryResponse.getResults()) {
            Map<String, Object> fieldValueMap = Maps.newHashMap();
            /*
             * Do not use doc.getFieldValueMap because it will return a map that returns only the first value on get.
             */
            for (Map.Entry<String, Object> entry : doc.entrySet()) {
                fieldValueMap.put(entry.getKey(), entry.getValue());
            }
            results.add(fieldValueMap);
        }
        return results;
    }

    private String createSolrQuery(String query, Map<String, Object> additionalFilters)
            throws RawSearchUnavailableException {
        if (Strings.isNullOrEmpty(rawSearchField)) {
            throw new RawSearchUnavailableException(name);
        }

        String baseQuery = String.format("%s:%s", rawSearchField, query.replace(":", " "));

        if (additionalFilters.isEmpty()) {
            return baseQuery;
        }

        StringBuilder sb = new StringBuilder(String.format("+(%s)", baseQuery));

        for (Map.Entry<String, Object> filter : additionalFilters.entrySet()) {
            sb.append(String.format(" +(%s:%s)", filter.getKey(), filter.getValue()));
        }
        return sb.toString();

    }

    @Override
    public List<Map<String, Object>> getDataByIds(List<String> ids, List<SortParameter> sort)
            throws SearchException {
        final int maxNumberOfIdsSolrSupports = 1000;
        List<List<String>> idsPart = Lists.partition(ids, maxNumberOfIdsSolrSupports);
        List<Map<String, Object>> results = Lists.newArrayList();

        List<SolrQuery.SortClause> sortClauses = Lists.newArrayList();

        for (SortParameter sortParameter : sort) {
            SolrQuery.ORDER order = SolrQuery.ORDER.desc;
            if (SortDirection.ASCENDING.equals(sortParameter.getDirection())) {
                order = SolrQuery.ORDER.asc;
            }

            sortClauses.add(new SolrQuery.SortClause(sortParameter.getFieldname(), order));
        }

        for (List<String> part : idsPart) {
            addResultsOfPartialQuery(part, results, sortClauses);
        }

        return results;
    }

    private void addResultsOfPartialQuery(List<String> ids, List<Map<String, Object>> results,
            List<SolrQuery.SortClause> sortClauses) throws SearchException {
        StringBuilder queryBuilder = new StringBuilder(Entity.INDEX_FIELD_ID);
        queryBuilder.append(" : (");
        boolean isFirst = true;
        for (String id : ids) {
            if (!isFirst) {
                queryBuilder.append(" OR ");
            }
            queryBuilder.append(id);
            isFirst = false;
        }
        queryBuilder.append(")");

        SolrQuery query = new SolrQuery(queryBuilder.toString());

        query.setRows(ids.size());
        query.setSorts(sortClauses);

        results.addAll(getMultiRawResults(query));
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof SolrIndex)) {
            return false;
        }

        SolrIndex other = (SolrIndex) obj;

        return new EqualsBuilder().append(name, other.name)//
                .append(rawSearchField, other.rawSearchField) //
                .append(solrDocumentCreator, other.solrDocumentCreator)//
                .append(facetedSearchLibrary, other.facetedSearchLibrary)//
                .append(solrServer, other.solrServer)//
                .append(indexDescription, other.indexDescription).isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(name)//
                .append(rawSearchField) //
                .append(solrDocumentCreator)//
                .append(facetedSearchLibrary)//
                .append(solrServer)//
                .append(indexDescription).toHashCode();
    }
}