Thuật toán / cấu trúc dữ liệu để trả lời những gì tôi có thể thực hiện công thức nấu ăn với bộ nguyên liệu này?


11

Chính thức, hãy s ( U , Q ) = { V | VUVQ } trong đó U , QV đều đại diện cho các tập hợp và U , cụ thể hơn, đại diện cho một tập hợp các tập hợp. Ví dụ, U có thể là một tập hợp (bộ) nguyên liệu cần thiết cho các công thức nấu ăn khác nhau trong một cuốn sách nấu ăn với Q đại diện cho bộ nguyên liệu tôi có V đại diện cho một công thức tôi có thể làm với những thành phần đó. Các truy vấn s ( U , Q) tương ứng với câu hỏi "Tôi có thể làm gì với những thành phần này?"

Điều tôi đang tìm kiếm là một biểu diễn dữ liệu lập chỉ mục U theo cách nó hỗ trợ các truy vấn hiệu quả của s ( U , Q ) trong đó Q và tất cả các thành viên của U nói chung sẽ nhỏ so với liên minh của tất cả các thành viên của U . Ngoài ra, tôi muốn nó có thể cập nhật U một cách hiệu quả (ví dụ: thêm hoặc xóa công thức).

Tôi không thể không nghĩ rằng vấn đề này phải được hiểu rõ, nhưng tôi chưa thể tìm thấy tên hoặc tài liệu tham khảo cho nó. Có ai biết về một chiến lược để giải quyết vấn đề này một cách hiệu quả hay một nơi mà tôi có thể đọc thêm về nó không?

Theo như suy nghĩ về một giải pháp, ai nghĩ tôi đã có được để xây dựng một cây quyết định cho tập U . Tại mỗi nút trong cây, câu hỏi "danh sách thành phần của bạn có chứa x không?" sẽ được hỏi với x được chọn để tối đa hóa số lượng thành viên của U bị loại bởi câu trả lời. Khi U được cập nhật, cây quyết định này sẽ cần được cân bằng lại để giảm thiểu số lượng câu hỏi cần thiết để tìm ra kết quả chính xác. Một suy nghĩ là đại diện cho U với một cái gì đó giống như một n chiều boolean 'octree' (nơi n là số thành phần duy nhất).

Tôi tin rằng "Những công thức nào có thể được thực hiện với những thành phần này?" có thể được trả lời bằng cách lấy sản phẩm cartesian của (bộ nguyên liệu cần thiết cho) công thức nấu ăn trong sách nấu ăn với quyền hạn của các thành phần có và lọc các cặp theo thứ tự kết quả cho các cặp trong đó cả hai yếu tố đều bằng nhau, nhưng đây không phải là một giải pháp hiệu quả, và điều tôi đang hỏi là làm thế nào để tối ưu hóa loại hoạt động này; Làm thế nào một người sẽ soạn cái này trong SQL sao cho nó hiệu quả và SQL làm gì để cho phép nó hiệu quả?

Mặc dù tôi sử dụng hình minh họa của một cuốn sách dạy nấu ăn và một bộ nguyên liệu, tôi dự đoán rằng số lượng 'công thức nấu ăn' và số lượng 'nguyên liệu' sẽ rất lớn (lên đến hàng trăm ngàn mỗi nguyên liệu), mặc dù số lượng nguyên liệu trong một công thức nhất định và số lượng thành phần trong một bộ thành phần nhất định sẽ tương đối nhỏ (có thể khoảng 10-50 cho một 'công thức' điển hình và khoảng 100 cho một 'bộ thành phần' điển hình). Ngoài ra, hoạt động phổ biến nhất sẽ là truy vấn s ( U , Q ), vì vậy nó phải tối ưu nhất. Điều này cũng có nghĩa là một thuật toán vũ phu đòi hỏi phải kiểm tra mọi công thức hoặc vận hành trên mọi thành phần sẽ tự nó chậm một cách không mong muốn. Với bộ nhớ đệm thông minh,


1
Một vấn đề cần được giải quyết dễ dàng với cơ sở dữ liệu SQL.
Robert Harvey

1
Dựa trên mô tả bổ sung của bạn, điều này nghe có vẻ như là một vấn đề quy mô của Orbitz. Công cụ tìm kiếm của Orbitz sử dụng công cụ Lisp di chuyển qua một tỷ điểm dữ liệu để có danh sách các chuyến bay phù hợp với hành trình cụ thể của bạn. Yêu cầu phi chức năng là nó phải trả về một giải pháp trong 10 giây hoặc ít hơn. Xem ở đây paulgraham.com/carl.html , mặc dù lưu ý rằng thông tin khá cũ.
Robert Harvey

Câu hỏi này khá rộng và có hai phần: cấu trúc dữ liệu và thuật toán để tìm các công thức nấu ăn hiện có là tập hợp con của các thành phần và cách chia tỷ lệ này cho dữ liệu lớn. Tôi nghĩ rằng đây sẽ là hai câu hỏi. Bạn thực sự không thể giải quyết phần dữ liệu lớn cho đến khi bạn thu hẹp phần thuật toán. user16054 đã nhận được trợ giúp về cách các bảng tham gia được sử dụng trong biểu diễn cơ sở dữ liệu quan hệ. Nếu câu hỏi này được thu hẹp vào phần thuật toán / cơ sở hạ tầng hoặc câu hỏi độc lập khác được hỏi, tôi có thể đưa ra đề xuất.
đá

Câu trả lời:


4

Đối với những con số bạn đã đưa ra, chỉ cần vũ phu nó.

Đây là một chương trình JavaScript bắt buộc 10 thành phần trong DB, 10 công thức trong DB, mỗi công thức cần 2 thành phần và tôi có sẵn 5 thành phần:

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);

Nó chạy trong 0 mili giây. Tôi đã chọn những con số nhỏ này để bạn có thể tự chạy nó một vài lần và tự thuyết phục bản thân nó làm những gì bạn muốn và tương đối không có lỗi.

Bây giờ hãy thay đổi nó để chúng tôi có 1000'000 thành phần trong DB, 1000'000 công thức trong DB, 50 thành phần cho mỗi công thức và 100 thành phần có sẵn cho tôi. Tức là các giá trị bằng hoặc lớn hơn trường hợp sử dụng lớn nhất bạn đã đưa ra.

Nó chạy trong 125 mili giây dưới nodejs, và đây là cách thực hiện ngu ngốc nhất mà hoàn toàn không cần nỗ lực để tối ưu hóa.


1
Trừ khi các yêu cầu của OP thay đổi, không có lý do gì để không thực hiện phương pháp này. Cấu trúc dữ liệu thông minh? Không đủ nhanh? Đúng. Duy trì và dễ hiểu? Chắc chắn nhất.
J Trana
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.