Алгоритм / структура даних, щоб відповісти "які рецепти я можу зробити з цього набору інгредієнтів?"


11

Формально нехай s ( U , Q ) = { V | VU і VQ }, де U , Q і V всі являють собою множини, а U , більш конкретно, являє собою набір множин. Для прикладу, U може бути набором (наборів) інгредієнтів, необхідних для різних рецептів у кулінарній книзі з Q, що представляє собою набір інгредієнтів, у мене V, що представляє рецепт, який я міг би скласти з цими інгредієнтами. Запит s ( U , Q) відповідає на запитання "Що все я можу зробити з цими інгредієнтами?"

Що я шукаю, це представлення даних, яке індексує U таким чином, що воно підтримує ефективні запити s ( U , Q ), де Q і всі члени U , як правило, невеликі порівняно з об'єднанням усіх членів U . Крім того, я хотів би, щоб він міг ефективно оновити U (наприклад, додати або видалити рецепт).

Я не можу не стверджувати, що цю проблему треба добре зрозуміти, але я не зміг знайти її ім’я чи посилання. Хтось знає про стратегію ефективного вирішення цього питання або про місце, де я можу прочитати більше про нього?

Наскільки думати про рішення, один думав , що я повинен був побудувати дерево рішень для безлічі U . На кожному вузлі дерева питання "чи містить ваш список інгредієнтів х ?" буде запропоновано з x, вибраним для максимізації кількості членів U, які усуваються у відповідь. По мірі того, як U оновлюється, це дерево рішень потрібно буде знову збалансувати, щоб мінімізувати кількість питань, необхідних для пошуку правильного результату. Інша думка полягає в тому, щоб зобразити U з чимось на зразок n -вимірної булевої 'octree' (де n - кількість унікальних інгредієнтів).

Я вважаю, що "Які рецепти можна зробити з цими інгредієнтами?" можна відповісти, взявши декартовий продукт (набір інгредієнтів, необхідних для) рецептів у кулінарній книзі з набором інгредієнтів, який є, та фільтруючи отримані впорядковані пари для пар, у яких обидва елементи рівні, але це не ефективне рішення, і про що я запитую - це оптимізація такого роду операцій; як би скласти це в SQL, щоб воно було ефективним, і що робить SQL, що дозволяє зробити це ефективним?

Хоча я використовую ілюстрацію кулінарної книги рецептів та набору інгредієнтів, я передбачаю, що кількість "рецептів" та кількість "інгредієнтів" будуть дуже великими (до сотень тисяч кожен), хоча кількість інгредієнтів у даному рецепті і кількість інгредієнтів у даному наборі інгредієнтів буде відносно невеликим (ймовірно, приблизно 10-50 для типового "рецепту" і приблизно 100 для типового "набору інгредієнтів"). Крім того, найпоширенішою операцією буде запит s ( U , Q ), тому він повинен бути найбільш оптимальним. Це також означає, що алгоритм грубої сили, який вимагає перевірити кожен рецепт або діяти над кожним інгредієнтом, сам по собі буде небажаним повільним. Із розумним кешуванням,


1
Проблема, яку слід легко вирішити за допомогою бази даних SQL.
Роберт Харві

1
Виходячи з вашого додаткового опису, це звучить як проблема в масштабі Орбіца. Пошукова система Orbitz використовує двигун Lisp, який просіює мільярд або більше точок даних, щоб отримати список рейсів, який буде відповідний вашому конкретному маршруту. Нефункціональна вимога полягає в тому, що він повинен повернути рішення протягом 10 секунд або менше. Дивіться тут paulgraham.com/carl.html , хоча зауважте, що інформація досить стара.
Роберт Харві

Це питання досить широке і має до нього дві частини: структуру даних та алгоритм пошуку існуючих рецептів, які є підмножинами інгредієнтів, і спосіб їх масштабування для великих даних. Я вважаю, що це два питання. Ви дійсно не можете вирішити велику частину даних, поки не звузите частину алгоритму. user16054 вже отримав допомогу щодо використання таблиць об'єднання в реляційному представленні бази даних. Якщо це питання звузиться до частини алгоритму / структури структури або було задано інше незалежне запитання, я можу запропонувати пропозиції.
скелястий

Відповіді:


4

Щодо цифр, які ви дали, просто нагнітайте це.

Ось програма JavaScript, яка жорстоко примушує її до 10 інгредієнтів у БД, 10 рецептів у БД, кожен рецепт потребує 2 інгредієнтів, і у мене є 5 інгредієнтів:

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 мілісекунд. Я вибрав ці невеликі числа, щоб ви могли кілька разів запустити його самостійно і переконати себе, що він робить те, що ви хочете, і порівняно не містить помилок.

Тепер змініть це так, щоб у нас було 1'000'000 інгредієнтів у БД, 1'000'000 рецептів у БД, 50 інгредієнтів на рецепт та 100 інгредієнтів, доступних мені. Тобто значення, які всі рівні або більше, ніж найбільший випадок використання, який ви дали.

Він працює за 125 мілісекунд під nodejs, і це з найдетальнішою реалізацією з абсолютно ніякими зусиллями для оптимізації.


1
Якщо не зміниться вимог ОП, немає причин не використовувати такий підхід. Розумна структура даних? Ні. Досить швидко? Так. Обслуговується легко і зрозуміло? Найбільш точно.
J Trana
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.