| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF 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 |
| * |
| * 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.apache.predictionio.examples.similarproduct |
| |
| import org.apache.predictionio.controller.LServing |
| |
| import breeze.stats.meanAndVariance |
| import breeze.stats.MeanAndVariance |
| |
| class Serving |
| extends LServing[Query, PredictedResult] { |
| |
| override |
| def serve(query: Query, |
| predictedResults: Seq[PredictedResult]): PredictedResult = { |
| |
| // MODFIED |
| val standard: Seq[Array[ItemScore]] = if (query.num == 1) { |
| // if query 1 item, don't standardize |
| predictedResults.map(_.itemScores) |
| } else { |
| // Standardize the score before combine |
| val mvList: Seq[MeanAndVariance] = predictedResults.map { pr => |
| meanAndVariance(pr.itemScores.map(_.score)) |
| } |
| |
| predictedResults.zipWithIndex |
| .map { case (pr, i) => |
| pr.itemScores.map { is => |
| // standardize score (z-score) |
| // if standard deviation is 0 (when all items have the same score, |
| // meaning all items are ranked equally), return 0. |
| val score = if (mvList(i).stdDev == 0) { |
| 0 |
| } else { |
| (is.score - mvList(i).mean) / mvList(i).stdDev |
| } |
| |
| ItemScore(is.item, score) |
| } |
| } |
| } |
| |
| // sum the standardized score if same item |
| val combined = standard.flatten // Array of ItemScore |
| .groupBy(_.item) // groupBy item id |
| .mapValues(itemScores => itemScores.map(_.score).reduce(_ + _)) |
| .toArray // array of (item id, score) |
| .sortBy(_._2)(Ordering.Double.reverse) |
| .take(query.num) |
| .map { case (k,v) => ItemScore(k, v) } |
| |
| PredictedResult(combined) |
| } |
| } |