• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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