All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dspace.app.suggestion.SolrSuggestionStorageServiceImpl Maven / Gradle / Ivy

The newest version!
/**
 * The contents of this file are subject to the license and copyright
 * detailed in the LICENSE and NOTICE files at the root of the source
 * tree and available online at
 *
 * http://www.dspace.org/license/
 */
package org.dspace.app.suggestion;

import static org.apache.commons.collections.CollectionUtils.isEmpty;

import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrQuery.SortClause;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.FacetField.Count;
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.FacetParams;
import org.dspace.content.Item;
import org.dspace.content.dto.MetadataValueDTO;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.util.UUIDUtils;
import org.springframework.beans.factory.annotation.Autowired;


/**
 * Service to deal with the local suggestion solr core used by the
 * SolrSuggestionProvider(s)
 *
 * @author Andrea Bollini (andrea.bollini at 4science dot it)
 *
 */
public class SolrSuggestionStorageServiceImpl implements SolrSuggestionStorageService {

    private static final Logger log = LogManager.getLogger(SolrSuggestionStorageServiceImpl.class);

    protected SolrClient solrSuggestionClient;

    @Autowired
    private ItemService itemService;

    /**
     * Get solr client which use suggestion core
     * 
     * @return solr client
     */
    protected SolrClient getSolr() {
        if (solrSuggestionClient == null) {
            String solrService = DSpaceServicesFactory.getInstance().getConfigurationService()
                    .getProperty("suggestion.solr.server", "http://localhost:8983/solr/suggestion");
            solrSuggestionClient = new HttpSolrClient.Builder(solrService).build();
        }
        return solrSuggestionClient;
    }

    @Override
    public void addSuggestion(Suggestion suggestion, boolean force, boolean commit)
            throws SolrServerException, IOException {
        if (force || !exist(suggestion)) {
            ObjectMapper jsonMapper = new JsonMapper();
            jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            SolrInputDocument document = new SolrInputDocument();
            document.addField(SOURCE, suggestion.getSource());
            // suggestion id is written as concatenation of
            // source + ":" + targetID + ":" + idPart (of externalDataObj)
            String suggestionFullID = suggestion.getID();
            document.addField(SUGGESTION_FULLID, suggestionFullID);
            document.addField(SUGGESTION_ID, suggestionFullID.split(":", 3)[2]);
            document.addField(TARGET_ID, suggestion.getTarget().getID().toString());
            document.addField(DISPLAY, suggestion.getDisplay());
            document.addField(TITLE, getFirstValue(suggestion, "dc", "title", null));
            document.addField(DATE, getFirstValue(suggestion, "dc", "date", "issued"));
            document.addField(CONTRIBUTORS, getAllValues(suggestion, "dc", "contributor", "author"));
            document.addField(ABSTRACT, getFirstValue(suggestion, "dc", "description", "abstract"));
            document.addField(CATEGORY, getAllValues(suggestion, "dc", "source", null));
            document.addField(EXTERNAL_URI, suggestion.getExternalSourceUri());
            document.addField(SCORE, suggestion.getScore());
            document.addField(PROCESSED, false);
            document.addField(EVIDENCES, jsonMapper.writeValueAsString(suggestion.getEvidences()));
            getSolr().add(document);
            if (commit) {
                getSolr().commit();
            }
        }
    }

    @Override
    public void commit() throws SolrServerException, IOException {
        getSolr().commit();
    }

    private List getAllValues(Suggestion suggestion, String schema, String element, String qualifier) {
        return suggestion.getMetadata().stream()
                .filter(st -> StringUtils.isNotBlank(st.getValue()) && StringUtils.equals(st.getSchema(), schema)
                        && StringUtils.equals(st.getElement(), element)
                        && StringUtils.equals(st.getQualifier(), qualifier))
                .map(st -> st.getValue()).collect(Collectors.toList());
    }

    private String getFirstValue(Suggestion suggestion, String schema, String element, String qualifier) {
        return suggestion.getMetadata().stream()
            .filter(st -> StringUtils.isNotBlank(st.getValue())
                && StringUtils.equals(st.getSchema(), schema)
                        && StringUtils.equals(st.getElement(), element)
                        && StringUtils.equals(st.getQualifier(), qualifier))
                .map(st -> st.getValue()).findFirst().orElse(null);
    }

    @Override
    public boolean exist(Suggestion suggestion) throws SolrServerException, IOException {
        SolrQuery query = new SolrQuery(
                SUGGESTION_FULLID + ":\"" + suggestion.getID() + "\" AND " + PROCESSED + ":true");
        return getSolr().query(query).getResults().getNumFound() == 1;
    }

    @Override
    public void deleteSuggestion(Suggestion suggestion) throws SolrServerException, IOException {
        getSolr().deleteById(suggestion.getID());
        getSolr().commit();
    }

    @Override
    public void flagSuggestionAsProcessed(Suggestion suggestion) throws SolrServerException, IOException {
        SolrInputDocument sdoc = new SolrInputDocument();
        sdoc.addField(SUGGESTION_FULLID, suggestion.getID());
        Map fieldModifier = new HashMap<>(1);
        fieldModifier.put("set", true);
        sdoc.addField(PROCESSED, fieldModifier); // add the map as the field value
        getSolr().add(sdoc);
        getSolr().commit();
    }

    @Override
    public void flagAllSuggestionAsProcessed(String source, String idPart) throws SolrServerException, IOException {
        SolrQuery query = new SolrQuery(SOURCE + ":" + source + " AND " + SUGGESTION_ID + ":\"" + idPart + "\"");
        query.setRows(Integer.MAX_VALUE);
        query.setFields(SUGGESTION_FULLID);
        SolrDocumentList results = getSolr().query(query).getResults();
        if (results.getNumFound() > 0) {
            for (SolrDocument rDoc : results) {
                SolrInputDocument sdoc = new SolrInputDocument();
                sdoc.addField(SUGGESTION_FULLID, rDoc.getFieldValue(SUGGESTION_FULLID));
                Map fieldModifier = new HashMap<>(1);
                fieldModifier.put("set", true);
                sdoc.addField(PROCESSED, fieldModifier); // add the map as the field value
                getSolr().add(sdoc);
            }
        }
        getSolr().commit();
    }

    @Override
    public void deleteTarget(SuggestionTarget target) throws SolrServerException, IOException {
        getSolr().deleteByQuery(
                SOURCE + ":" + target.getSource() + " AND " + TARGET_ID + ":" + target.getTarget().getID().toString());
        getSolr().commit();
    }

    @Override
    public long countAllTargets(Context context, String source) throws SolrServerException, IOException {
        SolrQuery solrQuery = new SolrQuery();
        solrQuery.setRows(0);
        solrQuery.setQuery(SOURCE + ":" + source);
        solrQuery.addFilterQuery(PROCESSED + ":false");
        solrQuery.setFacet(true);
        solrQuery.setFacetMinCount(1);
        solrQuery.addFacetField(TARGET_ID);
        solrQuery.setFacetLimit(Integer.MAX_VALUE);
        QueryResponse response = getSolr().query(solrQuery);
        return response.getFacetField(TARGET_ID).getValueCount();
    }

    @Override
    public long countUnprocessedSuggestionByTarget(Context context, String source, UUID target)
        throws SolrServerException, IOException {
        SolrQuery solrQuery = new SolrQuery();
        solrQuery.setRows(0);
        solrQuery.setQuery("*:*");
        solrQuery.addFilterQuery(
            SOURCE + ":" + source,
            TARGET_ID + ":" + target.toString(),
            PROCESSED + ":false");

        QueryResponse response = getSolr().query(solrQuery);
        return response.getResults().getNumFound();
    }

    @Override
    public List findAllUnprocessedSuggestions(Context context, String source, UUID target,
        int pageSize, long offset, boolean ascending) throws SolrServerException, IOException {

        SolrQuery solrQuery = new SolrQuery();
        solrQuery.setRows(pageSize);
        solrQuery.setStart((int) offset);
        solrQuery.setQuery("*:*");
        solrQuery.addFilterQuery(
            SOURCE + ":" + source,
            TARGET_ID + ":" + target.toString(),
            PROCESSED + ":false");

        if (ascending) {
            solrQuery.addSort(SortClause.asc("trust"));
        } else {
            solrQuery.addSort(SortClause.desc("trust"));
        }

        solrQuery.addSort(SortClause.desc("date"));
        solrQuery.addSort(SortClause.asc("title"));

        QueryResponse response = getSolr().query(solrQuery);
        List suggestions = new ArrayList();
        for (SolrDocument solrDoc : response.getResults()) {
            suggestions.add(convertSolrDoc(context, solrDoc, source));
        }
        return suggestions;

    }

    @Override
    public List findAllTargets(Context context, String source, int pageSize, long offset)
        throws SolrServerException, IOException {

        SolrQuery solrQuery = new SolrQuery();
        solrQuery.setRows(0);
        solrQuery.setQuery(SOURCE + ":" + source);
        solrQuery.addFilterQuery(PROCESSED + ":false");
        solrQuery.setFacet(true);
        solrQuery.setFacetMinCount(1);
        solrQuery.addFacetField(TARGET_ID);
        solrQuery.setParam(FacetParams.FACET_OFFSET, String.valueOf(offset));
        solrQuery.setFacetLimit((int) (pageSize));
        QueryResponse response = getSolr().query(solrQuery);
        FacetField facetField = response.getFacetField(TARGET_ID);
        List suggestionTargets = new ArrayList();
        int idx = 0;
        for (Count c : facetField.getValues()) {
            SuggestionTarget target = new SuggestionTarget();
            target.setSource(source);
            target.setTotal((int) c.getCount());
            target.setTarget(findItem(context, c.getName()));
            suggestionTargets.add(target);
            idx++;
        }
        return suggestionTargets;

    }

    @Override
    public Suggestion findUnprocessedSuggestion(Context context, String source, UUID target, String id)
        throws SolrServerException, IOException {

        SolrQuery solrQuery = new SolrQuery();
        solrQuery.setRows(1);
        solrQuery.setQuery("*:*");
        solrQuery.addFilterQuery(
            SOURCE + ":" + source,
            TARGET_ID + ":" + target.toString(),
            SUGGESTION_ID + ":\"" + id + "\"",
            PROCESSED + ":false");

        SolrDocumentList results = getSolr().query(solrQuery).getResults();
        return isEmpty(results) ? null : convertSolrDoc(context, results.get(0), source);
    }

    @Override
    public SuggestionTarget findTarget(Context context, String source, UUID target)
        throws SolrServerException, IOException {
        SolrQuery solrQuery = new SolrQuery();
        solrQuery.setRows(0);
        solrQuery.setQuery(SOURCE + ":" + source);
        solrQuery.addFilterQuery(
            TARGET_ID + ":" + target.toString(),
            PROCESSED + ":false");
        QueryResponse response = getSolr().query(solrQuery);
        SuggestionTarget sTarget = new SuggestionTarget();
        sTarget.setSource(source);
        sTarget.setTotal((int) response.getResults().getNumFound());
        Item itemTarget = findItem(context, target);
        if (itemTarget != null) {
            sTarget.setTarget(itemTarget);
        } else {
            return null;
        }
        return sTarget;
    }

    private Suggestion convertSolrDoc(Context context, SolrDocument solrDoc, String sourceName) {
        Item target = findItem(context, (String) solrDoc.getFieldValue(TARGET_ID));

        Suggestion suggestion = new Suggestion(sourceName, target, (String) solrDoc.getFieldValue(SUGGESTION_ID));
        suggestion.setDisplay((String) solrDoc.getFieldValue(DISPLAY));
        suggestion.getMetadata()
            .add(new MetadataValueDTO("dc", "title", null, null, (String) solrDoc.getFieldValue(TITLE)));
        suggestion.getMetadata()
            .add(new MetadataValueDTO("dc", "date", "issued", null, (String) solrDoc.getFieldValue(DATE)));
        suggestion.getMetadata().add(
            new MetadataValueDTO("dc", "description", "abstract", null, (String) solrDoc.getFieldValue(ABSTRACT)));

        suggestion.setExternalSourceUri((String) solrDoc.getFieldValue(EXTERNAL_URI));
        if (solrDoc.containsKey(CATEGORY)) {
            for (Object o : solrDoc.getFieldValues(CATEGORY)) {
                suggestion.getMetadata().add(
                    new MetadataValueDTO("dc", "source", null, null, (String) o));
            }
        }
        if (solrDoc.containsKey(CONTRIBUTORS)) {
            for (Object o : solrDoc.getFieldValues(CONTRIBUTORS)) {
                suggestion.getMetadata().add(
                    new MetadataValueDTO("dc", "contributor", "author", null, (String) o));
            }
        }
        String evidencesJson = (String) solrDoc.getFieldValue(EVIDENCES);
        ObjectMapper jsonMapper = new JsonMapper();
        jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        List evidences = new LinkedList();
        try {
            evidences = jsonMapper.readValue(evidencesJson, new TypeReference>() {});
        } catch (JsonProcessingException e) {
            log.error(e);
        }
        suggestion.getEvidences().addAll(evidences);
        return suggestion;
    }

    private Item findItem(Context context, UUID itemId) {
        try {
            return itemService.find(context, itemId);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    private Item findItem(Context context, String itemId) {
        return findItem(context, UUIDUtils.fromString(itemId));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy