Фильтрация набора данных на основе другого набора данных - PullRequest
0 голосов
/ 18 января 2019

У меня много пользователей, и у них есть любимые цвета. У меня есть набор данных - каждая из его записей имеет цветовые данные - и я хочу отправить электронное письмо каждому пользователю. В каждом письме пользователь будет видеть отфильтрованные данные, основанные на его / ее любимых цветах, что означает, что мне нужно отфильтровать этот набор данных на основе его любимых цветов.

Например; любимые цвета пользователей, как это:
[Пользователь1 :( «Зеленый», «Желтый»), Пользователь2 :( «Зеленый, Синий»), Пользователь3 :( «Красный»), Пользователь4 :( «Оранжевый», «Фиолетовый», «Красный»), Пользователь5 :( «Синий», «Желтый»)…]

Как эффективно отфильтровать этот набор данных по любимым цветам пользователя?

Самый простой способ - циклически проходить по списку пользователей и фильтровать набор данных по любимым цветам текущего пользователя на каждой итерации. Однако это может вызвать избыточные запросы для одинаковых или общих цветов. Итак, если у меня будет 1 миллион пользователей, я сделаю 1 миллион запросов к одному и тому же набору данных.

Может кто-нибудь предложить идею, чтобы сделать этот процесс более элегантным? Я сделаю это с Python, но ответ может быть независимым от языка.

Ответы [ 3 ]

0 голосов
/ 18 января 2019

Будет лучше, если вы предоставите больше информации о языке и инструментах / технологиях, которые вы используете.

Вопрос только в фильтрации существующего набора данных? Или я могу внести изменения в код? У меня есть одна идея, могу ли я добавить код.

Я представлял, как решить проблему, не используя никаких инструментов (например, с чистым JavaScript). В этом случае я предпочитаю иметь две таблицы User -> Color (которые вы указали выше) и Color -> User с отношениями между ними и обновлять обе таблицы одновременно. Посмотрите на фрагмент кода, чтобы понять, что я имею в виду.

Redis (база данных ключ-значение) будет отличным выбором для этого.

Я не могу вам больше помочь, потому что вопрос не содержит технической информации, но я просто оставляю свой ответ здесь. Возможно, это подтолкнет вас к любой идее:)

var USERS = {DefaultUser: {TestColor: true}};
var COLORS = {TestColor: {DefaultUser: true}};

function addColor (userId, color) {
	if (!COLORS[color]) COLORS[color] = {};
	COLORS[color][userId] = true;

	if (!USERS[userId]) USERS[userId] = {};
	USERS[userId][color] = true;
}

function removeColor (userId, color) {
	if (!COLORS[color]) return;
	delete COLORS[color][userId];

  if (!USERS[userId]) USERS[userId] = {};
	delete USERS[userId][color];
}

function findUsersByColor (color) {
	return Object.keys(COLORS[color] || {});
}

function addColorsToUsers () {
  addColor('User1', 'Green');
  addColor('User1', 'Yellow');
  addColor('User2', 'Green');
  addColor('User2', 'Blue');
  addColor('User3', 'Red');
  addColor('User4', 'Orange');
  addColor('User4', 'Purple');
  addColor('User4', 'Red');
  addColor('User5', 'Blue');
  addColor('User5', 'Yellow');
}

function runJob () {
  console.log('Result: findUsersByColor("Green")', findUsersByColor("Green"))
  removeColor("User1", "Green")
  console.log('Result: findUsersByColor("Green")', findUsersByColor("Green"))
}

addColorsToUsers();
runJob();
0 голосов
/ 18 января 2019

Продолжая идею @ jake2389, вы можете сделать несколько трюков. То, что вы действительно можете сделать, во многом зависит от того, насколько велик ваш набор данных и сколько раз вы можете разместить его в своей памяти (или своей базе данных). Очевидный способ улучшить производительность - это сделать кеширование. Предположим, у вас есть метод getRecordsForColors(colors), который выполняет реальную фильтрацию (или реальный запрос к БД). Какой-то очень наивный подход будет выглядеть следующим образом (обратите внимание, я не пробовал этот код, поэтому может быть много мелких ошибок):

cache = dict()

def getRecordsCached(colors):
    global cache
    if colors not in cache:
       records = getRecordsForColors(colors)
       cache[colors] = records
       return records
    else:
       return cache[colors]

Очевидный недостаток этого подхода заключается в том, что вы должны хранить в кэше все комбинации цветов, даже если они используются только одним пользователем, а это может быть много.

Более разумный подход - выбрать threshold, например, 3 цвета, для которых можно сохранить все комбинации:

cache = dict()

def getRecordsCached(colors):
    global cache
    if colors not in cache:
       records = getRecordsForColors(colors)
       if len(colors) < threshold:
          cache[colors] = records
       return records
    else:
       return cache[colors]

Это охватит большинство пользователей, и те пользователи с редкими длинными комбинациями будут выдавать несколько дублированных запросов.

Очевидно, что вам вообще не нужно использовать наивный dict кэш или кэш в памяти. Вы можете кэшировать данные в одной и той же БД или использовать специализированную для кеша БД, такую ​​как Memcached или Redis. Также вместо порога в форме длины colors вы можете использовать некоторую специализированную библиотеку кеша, которая поддерживает кэш LRU, или некоторую другую замену полиции

Наконец, если ваша логика заключается в том, что результат для данного набора цветов представляет собой просто объединение результатов для каждого цвета, вы можете попытаться покрыть эти редкие большие комбинации цветов на стороне клиента, кэшируя результаты для каждого цвета отдельно и затем, если комбинация цветов не находится непосредственно в кэше, вычислите ее, объединив элементы в кэшированных результатах для каждого цвета.

0 голосов
/ 18 января 2019

Поскольку это сугубо теоретический подход (вы не предоставляете, какую технологию вы хотите использовать), я бы предпочел отфильтровать запрос, который выбирает пользователей, имеющих одинаковые параметры соответствия (цвета).Теперь это можно сделать с помощью SQL-запроса или LINQ to SQL, если вы используете .NET.Если вы сможете предоставить больше информации о том, на каком языке вы будете пользоваться, я могу дать вам более конкретные ответы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...