001/*
002 * (C) Copyright 2019 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Salem Aouana
018 */
019
020package org.nuxeo.elasticsearch.hint;
021
022import org.elasticsearch.index.query.MoreLikeThisQueryBuilder;
023import org.elasticsearch.index.query.QueryBuilder;
024import org.elasticsearch.index.query.QueryBuilders;
025import org.nuxeo.ecm.core.api.repository.RepositoryManager;
026import org.nuxeo.ecm.core.query.sql.model.EsHint;
027import org.nuxeo.elasticsearch.api.ESHintQueryBuilder;
028import org.nuxeo.elasticsearch.api.ElasticSearchAdmin;
029import org.nuxeo.runtime.api.Framework;
030
031/**
032 * The implementation of {@link ESHintQueryBuilder} for the <strong>"more_like_this"</strong> Elasticsearch hint
033 * operator.
034 *
035 * @since 11.1
036 */
037public class MoreLikeThisESHintQueryBuilder implements ESHintQueryBuilder {
038
039    public static final int MORE_LIKE_THIS_MIN_TERM_FREQ = 1;
040
041    public static final int MORE_LIKE_THIS_MIN_DOC_FREQ = 3;
042
043    public static final int MORE_LIKE_THIS_MAX_QUERY_TERMS = 12;
044
045    /**
046     * {@inheritDoc}
047     * <p>
048     *
049     * @return {@link org.elasticsearch.index.query.MoreLikeThisQueryBuilder}
050     */
051    @Override
052    public QueryBuilder make(EsHint hint, String fieldName, Object value) {
053        String[] indexFields = hint.getIndexFieldNames();
054        String[] fields = indexFields.length > 0 ? indexFields : new String[] { fieldName };
055        return QueryBuilders.moreLikeThisQuery(fields, null, getItems(value))
056                            .analyzer(hint.analyzer)
057                            .minDocFreq(MORE_LIKE_THIS_MIN_DOC_FREQ)
058                            .minTermFreq(MORE_LIKE_THIS_MIN_TERM_FREQ)
059                            .maxQueryTerms(MORE_LIKE_THIS_MAX_QUERY_TERMS);
060    }
061
062    /**
063     * Build a single or an array of {@link MoreLikeThisQueryBuilder.Item} according to the value type. Where each
064     * {@link MoreLikeThisQueryBuilder.Item} represent a document request
065     *
066     * @param value represent what we are looking for. Can be <code>String</code> or an array of <code>String</code>
067     * @return the items / document requests
068     */
069    public static MoreLikeThisQueryBuilder.Item[] getItems(Object value) {
070        RepositoryManager rm = Framework.getService(RepositoryManager.class);
071        String repo = rm.getDefaultRepository().getName();
072        ElasticSearchAdmin esa = Framework.getService(ElasticSearchAdmin.class);
073        String esIndex = esa.getIndexNameForRepository(repo);
074        Object[] values;
075        if (value instanceof Object[]) {
076            values = (Object[]) value;
077        } else {
078            values = new Object[] { value };
079        }
080        MoreLikeThisQueryBuilder.Item[] ret = new MoreLikeThisQueryBuilder.Item[values.length];
081        for (int i = 0; i < values.length; i++) {
082            ret[i] = new MoreLikeThisQueryBuilder.Item(esIndex, (String) values[i]);
083        }
084        return ret;
085    }
086}