“Bu malzemelerle hangi tarifleri yapabilirim?” Cevabını veren algoritma / veri yapısı.


11

Resmi olarak, s ( U , Q ) = { V | VU ve VQ }, burada U , Q ve V'nin hepsi kümeleri temsil eder ve U , daha spesifik olarak bir kümeyi temsil eder. Örnek uğruna, U , bir yemek kitabındaki çeşitli tarifler için gerekli olan (bir dizi) içerik seti olabilir; Q , bu malzemelerle yapabileceğim bir tarifi temsil eden V sahip olduğum bileşen kümesini temsil eder. Sorgu s ( U , Q) "Bu malzemelerle ne yapabilirim?" sorusuna karşılık gelir.

Ne aradığım endeksler bir veri temsilidir U şekilde bu verimli sorguları desteklediğini s ( U , Q ) Q ve tüm üyeleri U genellikle üyelerinin hepsi birliği ile karşılaştırıldığında küçük olacaktır U . Ayrıca, etkin bir şekilde U güncellemesini istiyorum (örneğin, bir tarif ekleyin veya çıkarın).

Yardım edemem ama bu sorunun iyi anlaşılması gerektiğini düşünüyorum, ancak bunun için bir ad veya referans bulamadım. Bunu verimli bir şekilde çözme stratejisi veya hakkında daha fazla bilgi edinebileceğim bir yer bilen var mı?

Bir çözüm düşünmeye gelince, bir düşüncem U kümesi için bir karar ağacı oluşturmaktı . Ağaçtaki her düğümde "içerik listeniz x içeriyor mu?" cevap tarafından kaldırılan U üyesi sayısını en üst düzeye çıkarmak için seçilen x ile sorulur . Gibi U güncellenir, bu karar ağacı yeniden dengeli doğru sonucu bulmak için gerekli soruların sayısını en aza indirmek için olması gerekir. Başka bir düşünce, U'yu n boyutlu bir boole 'oktree' gibi bir şeyle temsil etmektir (burada n benzersiz bileşenlerin sayısıdır).

"Bu malzemelerle hangi tarifler yapılabilir?" yemek kitabındaki tariflerin kartezyen ürününü (için gerekli olan malzeme setlerini) alarak, içerdiği bileşenlerin güç seti ile ve her iki elementin eşit olduğu çiftler için elde edilen sıralı çiftleri filtreleyerek cevaplanabilir, ancak bu bir verimli bir çözümdür ve sorduğum şey, bu tür bir operasyonun nasıl optimize edileceği; SQL'de bunu verimli olacak şekilde nasıl oluşturabilir ve SQL'in etkili olmasına izin veren ne yapar?

Yemek tarifleri ve bir dizi malzemenin resmini kullanmama rağmen, 'tariflerin' sayısının ve 'içeriklerin' sayısının çok fazla (her biri yüzbinlerce) olacağını tahmin ediyorum belirli bir tarifte ve belirli bir bileşen setindeki bileşenlerin sayısı nispeten az olacaktır (tipik bir 'tarif' için muhtemelen 10-50 ve tipik bir 'içerik seti' için yaklaşık 100 olacaktır). Ayrıca, en yaygın işlem s ( U , Q ) sorgusu olacaktır , bu yüzden en uygun olmalıdır. Bu aynı zamanda her tarifi kontrol etmeyi veya her bileşen üzerinde çalışmayı gerektiren kaba kuvvet algoritmasının kendi başına istenmeyen bir şekilde yavaş olacağı anlamına gelir. Akıllı önbellekleme ile,


1
SQL veritabanı ile kolayca çözülmesi gereken bir problem.
Robert Harvey

1
Ek açıklamanıza dayanarak, bu Orbitz ölçeğinde bir soruna benziyor. Orbitz'in arama motoru, belirli seyahat programınıza uygun uçuşların listesini almak için bir milyar kadar veri noktasını atlayan bir Lisp motoru kullanır. İşlevsel olmayan bir gereklilik, bir çözümü 10 saniye veya daha kısa sürede döndürmesi gerektiğidir. Buraya bakınız paulgraham.com/carl.html , ancak bilgilerin oldukça eski olduğunu unutmayın.
Robert Harvey

Bu soru oldukça geniştir ve iki kısmı vardır: bileşenlerin alt kümeleri olan mevcut tarifleri bulmak için bir veri yapısı ve algoritma ve bunun büyük veriler için nasıl ölçeklendirileceği. Benim görüşüm, bunun iki soru olması gerektiğidir. Algoritma parçasını daraltana kadar büyük veri parçasını gerçekten ele alamazsınız. user16054 ilişkisel veritabanı gösteriminde birleştirme tablolarının nasıl kullanıldığı konusunda zaten yardım almıştır. Bu soru algoritma / veri yapısı kısmına daraltılırsa veya başka bir bağımsız soru sorulursa, önerilerde bulunabilirim.
kayalık

Yanıtlar:


4

Verdiğiniz sayılar için sadece kaba kuvvet uygula.

İşte kaba bir DB programı 10 içerik, DB 10 yemek tarifleri, her tarif 2 malzeme, ve ben mevcut 5 bileşen zorlar bir JavaScript programı:

var i, j;
var numIngredients = 10;
var numRecipes = 10;
var numIngredientsPerRecipe = 2;
var numIngredientsInQuery = 5;

function containsAll(needles, haystack){ 
  var i, len;
  for(i = 0 , len = needles.length; i < len; i++){
      if(haystack.indexOf(needles[i]) == -1) {
          return false;
      }
  }
  return true;
}

// Set up a fake DB of recipes
var ingredients = [];
for (i = 0; i < numIngredients; i++) {
    ingredients.push(i);
}
console.log('Here are the ingredients:', ingredients);

var recipes = [];
for (i = 0; i < numRecipes; i++) {
    var neededIngredients = [];
    for (j = 0; j < numIngredientsPerRecipe; j++) {
        neededIngredients.push(Math.floor(Math.random() * numRecipes));
    }
    recipes.push({ recipeId: i, needed: neededIngredients});
}
console.log('Here are the recipes:', recipes);

// Set up a fake query
var ingredientsAvailable = [];
for (i = 0; i < numIngredientsInQuery; i++) {
    ingredientsAvailable.push(Math.floor(Math.random() * numRecipes));
}

console.log("Here's a query:", ingredientsAvailable);

//Time how long brute force takes
var start = Date.now();
var result = [];
for (i = 0; i < numRecipes; i++) {
    var candidateRecipe = recipes[i];
    if (containsAll(candidateRecipe.needed, ingredientsAvailable)) {
        result.push(candidateRecipe);
    }
}
var end = Date.now();
console.log('Found ' + result.length + ' recipes in ' + (end - start) + ' milliseconds.');
console.log(result);

0 milisaniye içinde çalışır. Bu küçük sayıları seçtim, böylece kendiniz birkaç kez çalıştırabilir ve istediğinizi yaptığını ve nispeten hata içermediğini ikna edebilirsiniz.

Şimdi DB'de 1'000'000 bileşen, DB'de 1'000'000 tarif, tarif başına 50 bileşen ve benim için 100 içerik olacak şekilde değiştirin. Yani, verdiğiniz en büyük kullanım durumuna eşit veya daha büyük değerler.

Düğümler altında 125 milisaniye içinde çalışır ve bu kesinlikle optimize etmek için hiçbir çaba harcamadan en aptal uygulama ile.


1
OP'nin gereksinimleri değişmedikçe, bu tür bir yaklaşımı benimsememek için hiçbir neden yoktur. Akıllı veri yapısı? Hayır. Yeterince hızlı mı? Evet. Sürdürülebilir ve kolay anlaşılır mı? Kesinlikle.
J Trana
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.