com.frank.search.solr.core.ResultHelper.java Source code

Java tutorial

Introduction

Here is the source code for com.frank.search.solr.core.ResultHelper.java

Source

/*
 * Copyright 2012 - 2015 the original author or authors.
 *
 * 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 com.frank.search.solr.core;

import com.frank.search.solr.VersionUtil;
import com.frank.search.solr.core.query.*;
import com.frank.search.solr.core.query.result.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.solr.client.solrj.response.*;
import org.apache.solr.client.solrj.response.FacetField.Count;
import org.apache.solr.client.solrj.response.PivotField;
import org.apache.solr.client.solrj.response.TermsResponse.Term;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.util.NamedList;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.annotation.Id;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.repository.util.ClassUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.lang.annotation.Annotation;
import java.util.*;
import java.util.Map.Entry;

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

/**
 * Use Result Helper to extract various parameters from the QueryResponse and
 * convert it into a proper Format taking care of non existent and null elements
 * with the response.
 * 
 * @author Christoph Strobl
 * @author Francisco Spaeth
 */
final class ResultHelper {

    private ResultHelper() {
    }

    static Map<String, List<TermsFieldEntry>> convertTermsQueryResponseToTermsMap(QueryResponse response) {
        if (response == null || response.getTermsResponse() == null
                || response.getTermsResponse().getTermMap() == null) {
            return Collections.emptyMap();
        }

        TermsResponse termsResponse = response.getTermsResponse();
        Map<String, List<TermsFieldEntry>> result = new LinkedHashMap<String, List<TermsFieldEntry>>(
                termsResponse.getTermMap().size());

        for (Entry<String, List<Term>> entry : termsResponse.getTermMap().entrySet()) {
            List<TermsFieldEntry> terms = new ArrayList<TermsFieldEntry>(entry.getValue().size());
            for (Term term : entry.getValue()) {
                SimpleTermsFieldEntry termsEntry = new SimpleTermsFieldEntry(term.getTerm(), term.getFrequency());
                termsEntry.setField(entry.getKey());
                terms.add(termsEntry);
            }
            result.put(entry.getKey(), terms);
        }

        return result;
    }

    static Map<Field, Page<FacetFieldEntry>> convertFacetQueryResponseToFacetPageMap(FacetQuery query,
            QueryResponse response) {
        Assert.notNull(query, "Cannot convert response for 'null', query");

        if (!hasFacets(query, response)) {
            return Collections.emptyMap();
        }
        Map<Field, Page<FacetFieldEntry>> facetResult = new HashMap<Field, Page<FacetFieldEntry>>();

        if (CollectionUtils.isNotEmpty(response.getFacetFields())) {
            int initalPageSize = query.getFacetOptions().getPageable().getPageSize();
            for (FacetField facetField : response.getFacetFields()) {
                if (facetField != null && StringUtils.hasText(facetField.getName())) {
                    Field field = new SimpleField(facetField.getName());
                    if (CollectionUtils.isNotEmpty(facetField.getValues())) {
                        List<FacetFieldEntry> pageEntries = new ArrayList<FacetFieldEntry>(initalPageSize);
                        for (Count count : facetField.getValues()) {
                            if (count != null) {
                                pageEntries
                                        .add(new SimpleFacetFieldEntry(field, count.getName(), count.getCount()));
                            }
                        }
                        facetResult.put(field, new SolrResultPage<FacetFieldEntry>(pageEntries,
                                query.getFacetOptions().getPageable(), facetField.getValueCount(), null));
                    } else {
                        facetResult.put(field,
                                new SolrResultPage<FacetFieldEntry>(Collections.<FacetFieldEntry>emptyList(),
                                        query.getFacetOptions().getPageable(), 0, null));
                    }
                }
            }
        }
        return facetResult;
    }

    static Map<com.frank.search.solr.core.query.PivotField, List<FacetPivotFieldEntry>> convertFacetQueryResponseToFacetPivotMap(
            FacetQuery query, QueryResponse response) {

        if (VersionUtil.isSolr3XAvailable()) {
            // pivot facets are a solr 4+ Feature
            return Collections.emptyMap();
        }

        Map<com.frank.search.solr.core.query.PivotField, List<FacetPivotFieldEntry>> facetResult = new HashMap<com.frank.search.solr.core.query.PivotField, List<FacetPivotFieldEntry>>();
        NamedList<List<PivotField>> facetPivot = response.getFacetPivot();
        if (facetPivot != null && facetPivot.size() > 0) {
            for (int i = 0; i < facetPivot.size(); i++) {
                String name = facetPivot.getName(i);
                List<PivotField> pivotResult = facetPivot.get(name);
                facetResult.put(new SimplePivotField(name), convertPivotResult(pivotResult));
            }
        }

        return facetResult;
    }

    private static List<FacetPivotFieldEntry> convertPivotResult(List<PivotField> pivotResult) {
        if (CollectionUtils.isEmpty(pivotResult)) {
            return Collections.emptyList();
        }

        ArrayList<FacetPivotFieldEntry> pivotFieldEntries = new ArrayList<FacetPivotFieldEntry>();

        for (PivotField pivotField : pivotResult) {
            SimpleFacetPivotEntry pivotFieldEntry = new SimpleFacetPivotEntry(
                    new SimpleField(pivotField.getField()), String.valueOf(pivotField.getValue()),
                    pivotField.getCount());

            List<PivotField> pivot = pivotField.getPivot();
            if (pivot != null) {
                pivotFieldEntry.setPivot(convertPivotResult(pivot));
            }

            pivotFieldEntries.add(pivotFieldEntry);
        }

        return pivotFieldEntries;
    }

    /**
     * @param query
     * @param response
     * @return
     * @since 1.5
     */
    static Map<Field, Page<FacetFieldEntry>> convertFacetQueryResponseToRangeFacetPageMap(FacetQuery query,
            QueryResponse response) {
        Assert.notNull(query, "Cannot convert response for 'null', query");

        if (!hasFacets(query, response) || isEmpty(response.getFacetRanges())) {
            return Collections.emptyMap();
        }
        Map<Field, Page<FacetFieldEntry>> facetResult = new HashMap<Field, Page<FacetFieldEntry>>();

        Pageable pageable = query.getFacetOptions().getPageable();
        int initalPageSize = pageable.getPageSize();
        for (RangeFacet<?, ?> rangeFacet : response.getFacetRanges()) {

            if (rangeFacet == null || !StringUtils.hasText(rangeFacet.getName())) {
                continue;
            }

            Field field = new SimpleField(rangeFacet.getName());

            List<FacetFieldEntry> entries;
            long total;
            if (isNotEmpty(rangeFacet.getCounts())) {
                entries = new ArrayList<FacetFieldEntry>(initalPageSize);
                for (RangeFacet.Count count : rangeFacet.getCounts()) {
                    entries.add(new SimpleFacetFieldEntry(field, count.getValue(), count.getCount()));
                }
                total = rangeFacet.getCounts().size();
            } else {
                entries = Collections.<FacetFieldEntry>emptyList();
                total = 0;
            }

            facetResult.put(field, new SolrResultPage<FacetFieldEntry>(entries, pageable, total, null));

        }

        return facetResult;
    }

    static List<FacetQueryEntry> convertFacetQueryResponseToFacetQueryResult(FacetQuery query,
            QueryResponse response) {
        Assert.notNull(query, "Cannot convert response for 'null', query");

        if (!hasFacets(query, response)) {
            return Collections.emptyList();
        }

        List<FacetQueryEntry> facetResult = new ArrayList<FacetQueryEntry>();

        if (MapUtils.isNotEmpty(response.getFacetQuery())) {
            for (Entry<String, Integer> entry : response.getFacetQuery().entrySet()) {
                facetResult.add(new SimpleFacetQueryEntry(entry.getKey(), entry.getValue()));
            }
        }
        return facetResult;
    }

    static <T> List<HighlightEntry<T>> convertAndAddHighlightQueryResponseToResultPage(QueryResponse response,
            SolrResultPage<T> page) {
        if (response == null || MapUtils.isEmpty(response.getHighlighting()) || page == null) {
            return Collections.emptyList();
        }

        List<HighlightEntry<T>> mappedHighlights = new ArrayList<HighlightEntry<T>>(page.getSize());
        Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();

        for (T item : page) {
            HighlightEntry<T> highlightEntry = processHighlightingForPageEntry(highlighting, item);
            mappedHighlights.add(highlightEntry);
        }
        page.setHighlighted(mappedHighlights);
        return mappedHighlights;
    }

    private static <T> HighlightEntry<T> processHighlightingForPageEntry(
            Map<String, Map<String, List<String>>> highlighting, T pageEntry) {
        HighlightEntry<T> highlightEntry = new HighlightEntry<T>(pageEntry);
        Object itemId = getMappedId(pageEntry);

        Map<String, List<String>> highlights = highlighting.get(itemId.toString());
        if (MapUtils.isNotEmpty(highlights)) {
            for (Entry<String, List<String>> entry : highlights.entrySet()) {
                highlightEntry.addSnipplets(entry.getKey(), entry.getValue());
            }
        }
        return highlightEntry;
    }

    private static Object getMappedId(Object o) {
        if (ClassUtils.hasProperty(o.getClass(), "id")) {
            try {
                return FieldUtils.readDeclaredField(o, "id", true);
            } catch (IllegalAccessException e) {
                throw new MappingException("Id property could not be accessed!", e);
            }
        }

        for (java.lang.reflect.Field field : o.getClass().getDeclaredFields()) {
            Annotation annotation = AnnotationUtils.getAnnotation(field, Id.class);
            if (annotation != null) {
                try {
                    return FieldUtils.readField(field, o, true);
                } catch (IllegalArgumentException e) {
                    throw new MappingException("Id property could not be accessed!", e);
                } catch (IllegalAccessException e) {
                    throw new MappingException("Id property could not be accessed!", e);
                }
            }
        }
        throw new MappingException("Id property could not be found!");
    }

    private static boolean hasFacets(FacetQuery query, QueryResponse response) {
        return query.hasFacetOptions() && response != null;
    }

    static <T> Map<Object, GroupResult<T>> convertGroupQueryResponseToGroupResultMap(Query query,
            Map<String, Object> objectNames, QueryResponse response, SolrTemplate solrTemplate, Class<T> clazz) {

        GroupResponse groupResponse = response.getGroupResponse();
        SolrDocumentList sdl = response.getResults();

        if (groupResponse == null) {
            return Collections.emptyMap();
        }

        Map<Object, GroupResult<T>> result = new LinkedHashMap<Object, GroupResult<T>>();

        List<GroupCommand> values = groupResponse.getValues();
        for (GroupCommand groupCommand : values) {

            List<GroupEntry<T>> groupEntries = new ArrayList<GroupEntry<T>>();

            for (Group group : groupCommand.getValues()) {

                SolrDocumentList documentList = group.getResult();
                List<T> beans = solrTemplate.convertSolrDocumentListToBeans(documentList, clazz);
                Page<T> page = new PageImpl<T>(beans, query.getGroupOptions().getPageRequest(),
                        documentList.getNumFound());
                groupEntries.add(new SimpleGroupEntry<T>(group.getGroupValue(), page));
            }

            int matches = groupCommand.getMatches();
            Integer ngroups = groupCommand.getNGroups();
            String name = groupCommand.getName();

            PageImpl<GroupEntry<T>> page;
            if (ngroups != null) {
                page = new PageImpl<GroupEntry<T>>(groupEntries, query.getPageRequest(), ngroups.intValue());
            } else {
                page = new PageImpl<GroupEntry<T>>(groupEntries);
            }

            SimpleGroupResult<T> groupResult = new SimpleGroupResult<T>(matches, ngroups, name, page);
            result.put(name, groupResult);
            if (objectNames.containsKey(name)) {
                result.put(objectNames.get(name), groupResult);
            }
        }

        return result;
    }

    static Map<String, FieldStatsResult> convertFieldStatsInfoToFieldStatsResultMap(
            Map<String, FieldStatsInfo> fieldStatsInfo) {

        if (fieldStatsInfo == null) {
            return Collections.emptyMap();
        }

        Map<String, FieldStatsResult> result = new LinkedHashMap<String, FieldStatsResult>();
        for (Entry<String, FieldStatsInfo> entry : fieldStatsInfo.entrySet()) {

            FieldStatsInfo value = entry.getValue();

            if (value == null) {
                result.put(entry.getKey(), new SimpleFieldStatsResult());
                continue;
            }

            SimpleFieldStatsResult statsResult = populateStatsResultWithFieldStatsInfo(new SimpleFieldStatsResult(),
                    value);

            statsResult.setCountDistinct(value.getCountDistinct());
            statsResult.setDistinctValues(value.getDistinctValues());

            Map<String, List<FieldStatsInfo>> facets = value.getFacets();

            if (facets != null) {
                statsResult.setStatsResults(convertFieldStatsInfoToStatsResultMap(facets));
            }

            result.put(entry.getKey(), statsResult);
        }

        return result;
    }

    private static Map<String, Map<String, StatsResult>> convertFieldStatsInfoToStatsResultMap(
            Map<String, List<FieldStatsInfo>> statsInfo) {

        Map<String, Map<String, StatsResult>> result = new LinkedHashMap<String, Map<String, StatsResult>>();

        for (Entry<String, List<FieldStatsInfo>> entry : statsInfo.entrySet()) {
            Map<String, StatsResult> facetStatsValues = new LinkedHashMap<String, StatsResult>();

            for (FieldStatsInfo fieldStatsInfo : entry.getValue()) {

                SimpleStatsResult statsResult = populateStatsResultWithFieldStatsInfo(new SimpleStatsResult(),
                        fieldStatsInfo);
                facetStatsValues.put(fieldStatsInfo.getName(), statsResult);
            }

            result.put(entry.getKey(), facetStatsValues);
        }

        return result;
    }

    private static <T extends SimpleStatsResult> T populateStatsResultWithFieldStatsInfo(T statsResult,
            FieldStatsInfo value) {

        statsResult.setMax(value.getMax());
        statsResult.setMin(value.getMin());
        statsResult.setCount(value.getCount());
        statsResult.setMissing(value.getMissing());
        statsResult.setStddev(value.getStddev());
        statsResult.setSumOfSquares((Double) new DirectFieldAccessor(value).getPropertyValue("sumOfSquares"));

        Object mean = value.getMean();
        if (mean instanceof Double) {
            statsResult.setMean((Double) mean);
        }

        Object sum = value.getSum();
        if (sum instanceof Double) {
            statsResult.setSum((Double) sum);
        }

        return statsResult;
    }

}