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 17 package com.android.settings.intelligence.suggestions.ranking; 18 19 import android.content.Context; 20 import android.service.settings.suggestions.Suggestion; 21 22 import java.util.ArrayList; 23 import java.util.HashMap; 24 import java.util.List; 25 import java.util.Map; 26 27 /** 28 * Creates a set of interaction features (i.e., metrics) to represent each setting suggestion. These 29 * features currently include normalized time from previous events (shown, dismissed and clicked) 30 * for any particular suggestion and also counts of these events. These features are used as signals 31 * to find the best ranking for suggestion items. 32 * <p/> 33 * Copied from packages/apps/Settings/src/.../dashboard/suggestions/SuggestionFeaturizer 34 */ 35 public class SuggestionFeaturizer { 36 // Key of the features used for ranking. 37 public static final String FEATURE_IS_SHOWN = "is_shown"; 38 public static final String FEATURE_IS_DISMISSED = "is_dismissed"; 39 public static final String FEATURE_IS_CLICKED = "is_clicked"; 40 public static final String FEATURE_TIME_FROM_LAST_SHOWN = "time_from_last_shown"; 41 public static final String FEATURE_TIME_FROM_LAST_DISMISSED = "time_from_last_dismissed"; 42 public static final String FEATURE_TIME_FROM_LAST_CLICKED = "time_from_last_clicked"; 43 public static final String FEATURE_SHOWN_COUNT = "shown_count"; 44 public static final String FEATURE_DISMISSED_COUNT = "dismissed_count"; 45 public static final String FEATURE_CLICKED_COUNT = "clicked_count"; 46 47 // The following numbers are estimated from histograms. 48 public static final double TIME_NORMALIZATION_FACTOR = 2e10; 49 public static final double COUNT_NORMALIZATION_FACTOR = 500; 50 51 private final SuggestionEventStore mEventStore; 52 53 public SuggestionFeaturizer(Context context) { 54 mEventStore = SuggestionEventStore.get(context); 55 } 56 57 /** 58 * Extracts the features for each package name. 59 * 60 * @return A Map containing the features, keyed by the package names. Each map value contains 61 * another map with key-value pairs of the features. 62 */ 63 public Map<String, Map<String, Double>> featurize(List<Suggestion> suggestions) { 64 Map<String, Map<String, Double>> features = new HashMap<>(); 65 Long curTimeMs = System.currentTimeMillis(); 66 final List<String> suggestionIds = new ArrayList<>(suggestions.size()); 67 for (Suggestion suggestion : suggestions) { 68 suggestionIds.add(suggestion.getId()); 69 } 70 for (String id : suggestionIds) { 71 Map<String, Double> featureMap = new HashMap<>(); 72 features.put(id, featureMap); 73 Long lastShownTime = mEventStore.readMetric(id, 74 SuggestionEventStore.EVENT_SHOWN, 75 SuggestionEventStore.METRIC_LAST_EVENT_TIME); 76 Long lastDismissedTime = mEventStore.readMetric(id, 77 SuggestionEventStore.EVENT_DISMISSED, 78 SuggestionEventStore.METRIC_LAST_EVENT_TIME); 79 Long lastClickedTime = mEventStore.readMetric(id, 80 SuggestionEventStore.EVENT_CLICKED, 81 SuggestionEventStore.METRIC_LAST_EVENT_TIME); 82 featureMap.put(FEATURE_IS_SHOWN, booleanToDouble(lastShownTime > 0)); 83 featureMap.put(FEATURE_IS_DISMISSED, booleanToDouble(lastDismissedTime > 0)); 84 featureMap.put(FEATURE_IS_CLICKED, booleanToDouble(lastClickedTime > 0)); 85 featureMap.put(FEATURE_TIME_FROM_LAST_SHOWN, 86 normalizedTimeDiff(curTimeMs, lastShownTime)); 87 featureMap.put(FEATURE_TIME_FROM_LAST_DISMISSED, 88 normalizedTimeDiff(curTimeMs, lastDismissedTime)); 89 featureMap.put(FEATURE_TIME_FROM_LAST_CLICKED, 90 normalizedTimeDiff(curTimeMs, lastClickedTime)); 91 featureMap.put(FEATURE_SHOWN_COUNT, normalizedCount(mEventStore.readMetric(id, 92 SuggestionEventStore.EVENT_SHOWN, SuggestionEventStore.METRIC_COUNT))); 93 featureMap.put(FEATURE_DISMISSED_COUNT, normalizedCount(mEventStore.readMetric(id, 94 SuggestionEventStore.EVENT_DISMISSED, SuggestionEventStore.METRIC_COUNT))); 95 featureMap.put(FEATURE_CLICKED_COUNT, normalizedCount(mEventStore.readMetric(id, 96 SuggestionEventStore.EVENT_CLICKED, SuggestionEventStore.METRIC_COUNT))); 97 } 98 return features; 99 } 100 101 private static double booleanToDouble(boolean bool) { 102 return bool ? 1 : 0; 103 } 104 105 private static double normalizedTimeDiff(long curTimeMs, long preTimeMs) { 106 return Math.min(1, (curTimeMs - preTimeMs) / TIME_NORMALIZATION_FACTOR); 107 } 108 109 private static double normalizedCount(long count) { 110 return Math.min(1, count / COUNT_NORMALIZATION_FACTOR); 111 } 112 }