Ich habe viele Benutzer und sie haben Lieblingsfarben. Ich habe einen Datensatz - jeder seiner Datensätze enthält Farbdaten - und möchte jedem Benutzer eine E-Mail senden. In jeder E-Mail sieht der Benutzer die gefilterten Daten basierend auf seinen Lieblingsfarben, was bedeutet, dass ich diesen Datensatz basierend auf seinen Lieblingsfarben filtern muss.

Beispielsweise; Die Lieblingsfarben der Benutzer sind:
[Benutzer1 :( "Grün", "Gelb"), Benutzer2 :( "Grün, Blau"), Benutzer3 :( "Rot"), Benutzer4 :( "Orange", "Lila", "Rot"), User5 :( "Blau", "Gelb")…]

Wie kann ich diesen Datensatz effektiv nach den Lieblingsfarben des Benutzers filtern?

Am einfachsten ist es, die Benutzerliste zu durchlaufen und den Datensatz in jeder Iteration nach den Lieblingsfarben des aktuellen Benutzers zu filtern. Dies kann jedoch zu redundanten Abfragen für dieselben oder allgemeine Farben führen. Wenn ich also 1 Million Benutzer habe, werde ich 1 Million Anfragen an denselben Datensatz stellen.

Kann jemand eine Idee vorschlagen, um diesen Prozess eleganter zu gestalten? Ich werde es mit Python machen, aber die Antwort kann sprachunabhängig sein.

0
Mert Malcok 18 Jän. 2019 im 01:16

3 Antworten

Beste Antwort

Wenn Sie die Idee von @ jake2389 erweitern, können Sie verschiedene Tricks ausführen. Was Sie wirklich tun können, hängt stark davon ab, wie groß Ihr Datensatz ist und wie oft Sie ihn in Ihren Speicher (oder Ihre Datenbank) einfügen können. Der offensichtliche Weg, um die Leistung zu verbessern, besteht darin, etwas Caching durchzuführen. Angenommen, Sie haben eine Methode getRecordsForColors(colors), die die eigentliche Filterung (oder die echte Abfrage an die Datenbank) durchführt. Ein sehr naiver Ansatz würde so aussehen (beachten Sie, dass ich diesen Code nicht ausprobiert habe, so dass es viele kleine Fehler geben könnte):

cache = dict()

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

Der offensichtliche Nachteil dieses Ansatzes besteht darin, dass Sie alle Farbkombinationen im Cache halten müssen, auch wenn sie nur von einem Benutzer verwendet werden, und dies kann eine Menge sein.

Ein etwas klügerer Ansatz könnte darin bestehen, einige threshold auszuwählen, wie zum Beispiel 3 Farben, für die Sie alle Kombinationen speichern können:

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]

Dies deckt die meisten Benutzer ab, und Benutzer mit seltenen langen Kombinationen führen zu doppelten Abfragen.

Offensichtlich müssen Sie überhaupt keinen naiven dict -basierten Cache oder In-Memory-Cache verwenden. Sie können die Daten in derselben Datenbank zwischenspeichern oder eine für die Cache-Datenbank spezialisierte Datenbank wie Memcached oder Redis verwenden. Anstelle eines Schwellenwerts in Form einer Länge von colors können Sie auch eine spezielle Cache-Bibliothek verwenden, die einen LRU-Cache unterstützt, oder eine andere Ersatzpolizei

Wenn Ihre Logik lautet, dass das Ergebnis für einen bestimmten Satz von Farben nur eine Vereinigung der Ergebnisse für jede Farbe ist, können Sie versuchen, diese seltenen großen Farbkombinationen auf der Clientseite abzudecken, indem Sie die Ergebnisse für jede Farbe allein zwischenspeichern und dann, wenn die Die Farbkombination befindet sich nicht direkt im Cache. Berechnen Sie sie, indem Sie die Elemente in den zwischengespeicherten Ergebnissen für jede Farbe zusammenführen.

0
SergGr 18 Jän. 2019 im 02:14

Es ist besser, wenn Sie mehr Details zu der Sprache und den von Ihnen verwendeten Tools / Technologien angeben.

Ist die Frage nur beim Filtern des vorhandenen Datensatzes? Oder kann ich den Code ändern? Ich habe eine Idee, ob ich Code hinzufügen kann.

Ich stellte mir vor, wie ich das Problem lösen kann, ohne Werkzeuge zu verwenden (zum Beispiel mit reinem JavaScript). In diesem Fall bevorzuge ich zwei Tabellen User -> Color (die Sie oben angegeben haben) und Color -> User mit Beziehungen zwischen ihnen und aktualisiere beide Tabellen gleichzeitig. Überprüfen Sie das Code-Snippet, um zu sehen, was ich meine.

Redis (Schlüsselwertdatenbank) ist dafür eine gute Wahl.

Ich kann Ihnen nicht mehr helfen, da die Frage keine technischen Informationen enthält, aber ich lasse meine Antwort einfach hier. Vielleicht bringt dich das auf eine Idee :)

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
Max Martynov 18 Jän. 2019 im 10:01

Da dies streng theoretisch ist (Sie geben nicht an, welche Technologie Sie verwenden möchten), würde ich nach einer Abfrage filtern, die Benutzer mit denselben Übereinstimmungsoptionen (Farben) abruft. Dies kann jetzt entweder über SQL-Query oder LINQ to SQL erreicht werden, wenn Sie .NET verwenden. Wenn Sie weitere Informationen zu der von Ihnen verwendeten Sprache bereitstellen können, kann ich Ihnen genauere Antworten geben.

0
Niklas Henricson 17 Jän. 2019 im 22:25