com.cloudera.oryx.als.serving.web.RecommendToAnonymousServlet.java Source code

Java tutorial

Introduction

Here is the source code for com.cloudera.oryx.als.serving.web.RecommendToAnonymousServlet.java

Source

/*
 * Copyright (c) 2013, Cloudera, Inc. All Rights Reserved.
 *
 * Cloudera, Inc. licenses this file to you 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
 *
 * This software 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.cloudera.oryx.als.serving.web;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.common.collect.Lists;
import org.apache.commons.math3.util.Pair;

import com.cloudera.oryx.als.common.Rescorer;
import com.cloudera.oryx.common.LangUtils;
import com.cloudera.oryx.als.common.NoSuchItemException;
import com.cloudera.oryx.als.common.NotReadyException;
import com.cloudera.oryx.als.common.OryxRecommender;
import com.cloudera.oryx.als.serving.RescorerProvider;

/**
 * <p>Responds to a GET request to
 * {@code /recommendToAnonymous/[itemID1(=value1)](/[itemID2(=value2)]/...)?howMany=n[&rescorerParams=...]},
 * and in turn calls {@link OryxRecommender#recommendToAnonymous(String[], float[], int, Rescorer)}
 * with the supplied values. That is, 1 or more item IDs are supplied, which may each optionally correspond to
 * a value or else default to 1. If howMany is not specified, defaults to
 * {@link AbstractALSServlet#DEFAULT_HOW_MANY}.</p>
 *
 * <p>Unknown item IDs are ignored, unless all are unknown, in which case a
 * {@link HttpServletResponse#SC_BAD_REQUEST} status is returned.</p>
 *
 * <p>Outputs item/score pairs like {@link RecommendServlet} does.</p>
 *
 * <p>This does something slightly different from {@link com.cloudera.oryx.als.serving.web.SimilarityServlet};
 * see {@link OryxRecommender#recommendToAnonymous(String[], float[], int)}.</p>
 *
 * @author Sean Owen
 * @see com.cloudera.oryx.als.serving.web.SimilarityServlet
 */
public final class RecommendToAnonymousServlet extends AbstractALSServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {

        CharSequence pathInfo = request.getPathInfo();
        if (pathInfo == null) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No path");
            return;
        }
        Iterator<String> pathComponents = SLASH.split(pathInfo).iterator();
        Pair<String[], float[]> itemIDsAndValue;
        try {
            itemIDsAndValue = parseItemValuePairs(pathComponents);
        } catch (NoSuchElementException nsee) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, nsee.toString());
            return;
        }

        if (itemIDsAndValue.getFirst().length == 0) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No items");
            return;
        }

        String[] itemIDs = itemIDsAndValue.getFirst();
        float[] values = itemIDsAndValue.getSecond();

        OryxRecommender recommender = getRecommender();
        RescorerProvider rescorerProvider = getRescorerProvider();
        try {
            Rescorer rescorer = rescorerProvider == null ? null
                    : rescorerProvider.getRecommendToAnonymousRescorer(itemIDs, recommender,
                            getRescorerParams(request));
            output(response, recommender.recommendToAnonymous(itemIDs, values, getHowMany(request), rescorer));
        } catch (NotReadyException nre) {
            response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, nre.toString());
        } catch (NoSuchItemException nsie) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, nsie.toString());
        } catch (IllegalArgumentException iae) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, iae.toString());
        }
    }

    static Pair<String[], float[]> parseItemValuePairs(Iterator<String> pathComponents) {
        List<Pair<String, Float>> itemValuePairs = Lists.newArrayListWithCapacity(1);
        while (pathComponents.hasNext()) {
            itemValuePairs.add(parseItemValue(pathComponents.next()));
        }

        int size = itemValuePairs.size();
        String[] itemIDs = new String[size];
        float[] values = new float[size];
        for (int i = 0; i < size; i++) {
            Pair<String, Float> itemValuePair = itemValuePairs.get(i);
            itemIDs[i] = itemValuePair.getFirst();
            Float value = itemValuePair.getSecond();
            values[i] = value == null ? 1.0f : value;
        }

        return new Pair<String[], float[]>(itemIDs, values);
    }

    private static Pair<String, Float> parseItemValue(String s) {
        int equals = s.indexOf('=');
        if (equals < 0) {
            return new Pair<String, Float>(s, null);
        }
        return new Pair<String, Float>(s.substring(0, equals), LangUtils.parseFloat(s.substring(equals + 1)));
    }

}