org.efaps.admin.index.Searcher.java Source code

Java tutorial

Introduction

Here is the source code for org.efaps.admin.index.Searcher.java

Source

/*
 * Copyright 2003 - 2016 The eFaps Team
 *
 * 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 org.efaps.admin.index;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.EnumUtils;
import org.apache.lucene.document.Document;
import org.apache.lucene.facet.FacetResult;
import org.apache.lucene.facet.Facets;
import org.apache.lucene.facet.FacetsCollector;
import org.apache.lucene.facet.FacetsConfig;
import org.apache.lucene.facet.FacetsConfig.DimConfig;
import org.apache.lucene.facet.LabelAndValue;
import org.apache.lucene.facet.taxonomy.FastTaxonomyFacetCounts;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryparser.flexible.core.QueryNodeException;
import org.apache.lucene.queryparser.flexible.standard.StandardQueryParser;
import org.apache.lucene.queryparser.flexible.standard.config.StandardQueryConfigHandler;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TopFieldDocs;
import org.efaps.admin.EFapsSystemConfiguration;
import org.efaps.admin.KernelSettings;
import org.efaps.admin.access.AccessTypeEnums;
import org.efaps.admin.datamodel.Type;
import org.efaps.admin.index.Indexer.Key;
import org.efaps.db.Instance;
import org.efaps.json.index.SearchResult;
import org.efaps.json.index.result.DimValue;
import org.efaps.json.index.result.Dimension;
import org.efaps.json.index.result.Element;
import org.efaps.util.EFapsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The Class Search.
 *
 * @author The eFaps Team
 */
public final class Searcher {

    /**
     * Logging instance used in this class.
     */
    private static final Logger LOG = LoggerFactory.getLogger(Searcher.class);

    /** The types. */
    private final Map<Type, List<Instance>> typeMapping = new HashMap<>();

    /** The docs. */
    private final Map<Instance, Element> elements = new LinkedHashMap<>();

    /**
     * Instantiates a new search.
     */
    private Searcher() {
    }

    /**
     * Search.
     *
     * @param _search the search
     * @return the search result
     * @throws EFapsException on error
     */
    protected SearchResult executeSearch(final ISearch _search) throws EFapsException {
        final SearchResult ret = new SearchResult();
        try {
            LOG.debug("Starting search with: {}", _search.getQuery());
            final StandardQueryParser queryParser = new StandardQueryParser(Index.getAnalyzer());
            queryParser.setAllowLeadingWildcard(true);
            if (EFapsSystemConfiguration.get().containsAttributeValue(KernelSettings.INDEXDEFAULTOP)) {
                queryParser.setDefaultOperator(EnumUtils.getEnum(StandardQueryConfigHandler.Operator.class,
                        EFapsSystemConfiguration.get().getAttributeValue(KernelSettings.INDEXDEFAULTOP)));
            } else {
                queryParser.setDefaultOperator(StandardQueryConfigHandler.Operator.AND);
            }
            final Query query = queryParser.parse(_search.getQuery(), "ALL");

            final IndexReader reader = DirectoryReader.open(Index.getDirectory());
            Sort sort = _search.getSort();
            if (sort == null) {
                sort = new Sort(new SortField(Key.CREATED.name(), SortField.Type.LONG, true));
            }

            final FacetsConfig facetConfig = Index.getFacetsConfig();
            final DirectoryTaxonomyReader taxoReader = new DirectoryTaxonomyReader(Index.getTaxonomyDirectory());

            final IndexSearcher searcher = new IndexSearcher(reader);
            final FacetsCollector fc = new FacetsCollector();

            final TopFieldDocs topFieldDocs = FacetsCollector.search(searcher, query, _search.getNumHits(), sort,
                    fc);

            if (_search.getConfigs().contains(SearchConfig.ACTIVATE_DIMENSION)) {
                final Facets facets = new FastTaxonomyFacetCounts(taxoReader, facetConfig, fc);

                for (final FacetResult result : facets.getAllDims(1000)) {
                    LOG.debug("FacetResult {}.", result);
                    final DimConfig dimConfig = facetConfig.getDimConfig(result.dim);
                    final Dimension retDim = new Dimension().setKey(result.dim);
                    ret.getDimensions().add(retDim);
                    for (final LabelAndValue labelValue : result.labelValues) {
                        final DimValue dimValue = new DimValue().setLabel(labelValue.label)
                                .setValue(labelValue.value.intValue());
                        dimValue.setPath(new String[] { retDim.getKey() });
                        retDim.getValues().add(dimValue);
                        if (dimConfig.hierarchical) {
                            addSubDimension(facets, dimValue, result.dim, labelValue.label);
                        }
                    }
                }
            }
            ret.setHitCount(topFieldDocs.totalHits);
            if (ret.getHitCount() > 0) {
                final ScoreDoc[] hits = topFieldDocs.scoreDocs;

                LOG.debug("Found {} hits.", hits.length);
                for (int i = 0; i < hits.length; ++i) {
                    final Document doc = searcher.doc(hits[i].doc);
                    final String oid = doc.get(Key.OID.name());
                    final String text = doc.get(Key.MSGPHRASE.name());
                    LOG.debug("{}. {}\t {}", i + 1, oid, text);
                    final Instance instance = Instance.get(oid);
                    final List<Instance> list;
                    if (this.typeMapping.containsKey(instance.getType())) {
                        list = this.typeMapping.get(instance.getType());
                    } else {
                        list = new ArrayList<Instance>();
                        this.typeMapping.put(instance.getType(), list);
                    }
                    list.add(instance);
                    final Element element = new Element().setOid(oid).setText(text);
                    for (final Entry<String, Collection<String>> entry : _search.getResultFields().entrySet()) {
                        for (final String name : entry.getValue()) {
                            final String value = doc.get(name);
                            if (value != null) {
                                element.addField(name, value);
                            }
                        }
                    }
                    this.elements.put(instance, element);
                }
            }
            reader.close();
            checkAccess();
            ret.getElements().addAll(this.elements.values());
        } catch (final IOException | QueryNodeException e) {
            LOG.error("Catched Exception", e);
        }
        return ret;
    }

    /**
     * Recursive method to get the sub dimension.
     *
     * @param _facets the facets
     * @param _dimValue the _dim value
     * @param _dim the _dim
     * @param _path the _path
     * @throws IOException Signals that an I/O exception has occurred.
     */
    private void addSubDimension(final Facets _facets, final DimValue _dimValue, final String _dim,
            final String _path) throws IOException {
        final FacetResult result = _facets.getTopChildren(1000, _dim, _path);
        if (result != null) {
            LOG.debug("FacetResult {}.", result);
            for (final LabelAndValue labelValue : result.labelValues) {
                final DimValue dimValue = new DimValue().setLabel(labelValue.label)
                        .setValue(labelValue.value.intValue());
                dimValue.setPath(ArrayUtils.addAll(_dimValue.getPath(), result.path));
                _dimValue.getChildren().add(dimValue);
                addSubDimension(_facets, dimValue, _dim, _path + "/" + labelValue.label);
            }
        }
    }

    /**
     * Check access.
     *
     * @throws EFapsException on error
     */
    private void checkAccess() throws EFapsException {
        // check the access for the given instances
        final Map<Instance, Boolean> accessmap = new HashMap<Instance, Boolean>();
        for (final Entry<Type, List<Instance>> entry : this.typeMapping.entrySet()) {
            accessmap.putAll(entry.getKey().checkAccess(entry.getValue(), AccessTypeEnums.SHOW.getAccessType()));
        }
        this.elements.entrySet().removeIf(entry -> accessmap.size() > 0
                && (!accessmap.containsKey(entry.getKey()) || !accessmap.get(entry.getKey())));
    }

    /**
     * Search.
     *
     * @param _query the query
     * @return the search result
     * @throws EFapsException on error
     */
    public static SearchResult search(final String _query) throws EFapsException {
        final ISearch searchDef = Index.getSearch();
        searchDef.setQuery(_query);
        return search(searchDef);
    }

    /**
     * Search.
     *
     * @param _search the search
     * @return the search result
     * @throws EFapsException on error
     */
    public static SearchResult search(final ISearch _search) throws EFapsException {
        return new Searcher().executeSearch(_search);
    }
}