1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 package com.android.settings.dashboard.suggestions; 17 18 import java.util.HashMap; 19 import java.util.List; 20 import java.util.Map; 21 22 /** 23 * Creates a set of interaction features (i.e., metrics) to represent each setting suggestion. These 24 * features currently include normalized time from previous events (shown, dismissed and clicked) 25 * for any particular suggestion and also counts of these events. These features are used as signals 26 * to find the best ranking for suggestion items. 27 */ 28 public class SuggestionFeaturizer { 29 30 // Key of the features used for ranking. 31 public static final String FEATURE_IS_SHOWN = "is_shown"; 32 public static final String FEATURE_IS_DISMISSED = "is_dismissed"; 33 public static final String FEATURE_IS_CLICKED = "is_clicked"; 34 public static final String FEATURE_TIME_FROM_LAST_SHOWN = "time_from_last_shown"; 35 public static final String FEATURE_TIME_FROM_LAST_DISMISSED = "time_from_last_dismissed"; 36 public static final String FEATURE_TIME_FROM_LAST_CLICKED = "time_from_last_clicked"; 37 public static final String FEATURE_SHOWN_COUNT = "shown_count"; 38 public static final String FEATURE_DISMISSED_COUNT = "dismissed_count"; 39 public static final String FEATURE_CLICKED_COUNT = "clicked_count"; 40 41 // The following numbers are estimated from histograms. 42 public static final double TIME_NORMALIZATION_FACTOR = 2e10; 43 public static final double COUNT_NORMALIZATION_FACTOR = 500; 44 45 private final EventStore mEventStore; 46 47 /** 48 * Constructor 49 * 50 * @param eventStore An instance of {@code EventStore} which maintains the recorded suggestion 51 * events. 52 */ SuggestionFeaturizer(EventStore eventStore)53 public SuggestionFeaturizer(EventStore eventStore) { 54 mEventStore = eventStore; 55 } 56 57 /** 58 * Extracts the features for each package name. 59 * 60 * @param pkgNames: List of package names for which features are queried. 61 * @return A Map containing the features, keyed by the package names. Each map value contains 62 * another map with key-value pairs of the features. 63 */ featurize(List<String> pkgNames)64 public Map<String, Map<String, Double>> featurize(List<String> pkgNames) { 65 Map<String, Map<String, Double>> features = new HashMap<>(); 66 Long curTimeMs = System.currentTimeMillis(); 67 for (String pkgName : pkgNames) { 68 Map<String, Double> featureMap = new HashMap<>(); 69 features.put(pkgName, featureMap); 70 Long lastShownTime = mEventStore 71 .readMetric(pkgName, EventStore.EVENT_SHOWN, EventStore.METRIC_LAST_EVENT_TIME); 72 Long lastDismissedTime = mEventStore.readMetric(pkgName, EventStore.EVENT_DISMISSED, 73 EventStore.METRIC_LAST_EVENT_TIME); 74 Long lastClickedTime = mEventStore.readMetric(pkgName, EventStore.EVENT_CLICKED, 75 EventStore.METRIC_LAST_EVENT_TIME); 76 featureMap.put(FEATURE_IS_SHOWN, booleanToDouble(lastShownTime > 0)); 77 featureMap.put(FEATURE_IS_DISMISSED, booleanToDouble(lastDismissedTime > 0)); 78 featureMap.put(FEATURE_IS_CLICKED, booleanToDouble(lastClickedTime > 0)); 79 featureMap.put(FEATURE_TIME_FROM_LAST_SHOWN, 80 normalizedTimeDiff(curTimeMs, lastShownTime)); 81 featureMap.put(FEATURE_TIME_FROM_LAST_DISMISSED, 82 normalizedTimeDiff(curTimeMs, lastDismissedTime)); 83 featureMap.put(FEATURE_TIME_FROM_LAST_CLICKED, 84 normalizedTimeDiff(curTimeMs, lastClickedTime)); 85 featureMap.put(FEATURE_SHOWN_COUNT, normalizedCount(mEventStore 86 .readMetric(pkgName, EventStore.EVENT_SHOWN, EventStore.METRIC_COUNT))); 87 featureMap.put(FEATURE_DISMISSED_COUNT, normalizedCount(mEventStore 88 .readMetric(pkgName, EventStore.EVENT_DISMISSED, EventStore.METRIC_COUNT))); 89 featureMap.put(FEATURE_CLICKED_COUNT, normalizedCount(mEventStore 90 .readMetric(pkgName, EventStore.EVENT_CLICKED, EventStore.METRIC_COUNT))); 91 } 92 return features; 93 } 94 booleanToDouble(boolean bool)95 private static double booleanToDouble(boolean bool) { 96 return bool ? 1 : 0; 97 } 98 normalizedTimeDiff(long curTimeMs, long preTimeMs)99 private static double normalizedTimeDiff(long curTimeMs, long preTimeMs) { 100 return Math.min(1, (curTimeMs - preTimeMs) / TIME_NORMALIZATION_FACTOR); 101 } 102 normalizedCount(long count)103 private static double normalizedCount(long count) { 104 return Math.min(1, count / COUNT_NORMALIZATION_FACTOR); 105 } 106 } 107