โครงสร้างอัลกอริทึม / ข้อมูลเพื่อตอบ“ ฉันสามารถทำสูตรอะไรได้บ้างกับชุดส่วนผสมนี้”


11

เป็นทางการให้s ( U , Q ) = { V | VUและVQ } โดยที่U , Q , และVทั้งหมดเป็นตัวแทนของชุดและUโดยเฉพาะเจาะจงมากขึ้นแสดงชุดของชุด เพื่อเป็นตัวอย่างคุณอาจเป็นชุดของส่วนผสม (ชุด) ที่จำเป็นสำหรับสูตรอาหารต่าง ๆ ในตำราอาหารที่มีQแทนชุดส่วนผสมที่ฉันมีVแทนสูตรที่ฉันสามารถทำกับส่วนผสมเหล่านั้นได้ แบบสอบถามs ( U , Q) สอดคล้องกับคำถาม "ฉันสามารถทำอะไรกับส่วนผสมเหล่านี้ได้บ้าง?"

สิ่งที่ฉันกำลังมองหาคือการแสดงข้อมูลที่ดัชนีUในลักษณะที่สนับสนุนการสืบค้นที่มีประสิทธิภาพของs ( U , Q ) โดยที่Qและสมาชิกทั้งหมดของUจะมีขนาดเล็กเมื่อเทียบกับสหภาพของสมาชิกทั้งหมดของU . นอกจากนี้ฉันต้องการให้อัปเดตUอย่างมีประสิทธิภาพ(เช่นเพิ่มหรือลบสูตรอาหาร)

ฉันไม่สามารถช่วยได้ แต่คิดว่าปัญหานี้ต้องเข้าใจดี แต่ฉันไม่สามารถหาชื่อหรือข้อมูลอ้างอิงได้ ใครบ้างรู้กลยุทธ์ในการแก้ปัญหานี้อย่างมีประสิทธิภาพหรือสถานที่ที่ฉันสามารถอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้?

เท่าที่ความคิดเกี่ยวกับการแก้ปัญหาหนึ่งคิดว่าผมคือการสร้างต้นไม้ตัดสินใจสำหรับชุดU ที่แต่ละโหนดในต้นไม้คำถาม "รายการส่วนผสมของคุณมีxหรือไม่" จะถูกถามด้วยx ที่เลือกเพื่อเพิ่มจำนวนสมาชิกของUที่ถูกกำจัดโดยคำตอบ เมื่อUได้รับการปรับปรุงทรีการตัดสินใจนี้จะต้องมีการปรับสมดุลใหม่เพื่อลดจำนวนคำถามที่จำเป็นในการค้นหาผลลัพธ์ที่ถูกต้อง อีกความคิดหนึ่งคือการเป็นตัวแทนของUด้วยสิ่งที่คล้ายกับบูลีนn -dimensional 'octree' (โดยที่nคือจำนวนของส่วนผสมเฉพาะ)

ฉันเชื่อว่า "สูตรใดบ้างที่สามารถทำด้วยส่วนผสมเหล่านี้ได้?" สามารถตอบได้โดยการใช้ผลิตภัณฑ์คาร์ทีเซียนของ (ชุดของส่วนผสมที่จำเป็นสำหรับ) สูตรในตำราอาหารที่มี powerset ของส่วนผสมที่มีและกรองคู่สั่งที่เกิดขึ้นสำหรับคู่ซึ่งองค์ประกอบทั้งสองเท่ากัน แต่นี่ไม่ใช่ โซลูชันที่มีประสิทธิภาพและสิ่งที่ฉันถามคือวิธีเพิ่มประสิทธิภาพการทำงานประเภทนี้ เราจะเขียนสิ่งนี้ใน SQL อย่างไรเพื่อให้มีประสิทธิภาพและ SQL ทำอะไรที่ทำให้สิ่งนี้มีประสิทธิภาพ

แม้ว่าฉันจะใช้ภาพประกอบตำราอาหารและชุดของส่วนผสมฉันคาดว่าจำนวนของ 'สูตร' และจำนวนของ 'ส่วนผสม' จะมีขนาดใหญ่มาก (มากถึงแสนชิ้น) แม้ว่าจำนวนของส่วนผสม ในสูตรที่กำหนดและจำนวนของส่วนผสมในชุดส่วนผสมที่กำหนดจะค่อนข้างเล็ก (อาจประมาณ 10-50 สำหรับ 'สูตร' ทั่วไปและประมาณ 100 สำหรับ 'ชุดส่วนผสม' ทั่วไป) นอกจากนี้การดำเนินงานที่พบมากที่สุดจะเป็นแบบสอบถามs ( U , Q ) ดังนั้นจึงควรจะเหมาะสมที่สุด ซึ่งหมายความว่าอัลกอริทึมแรงเดรัจฉานที่ต้องตรวจสอบทุกสูตรหรือใช้งานกับส่วนผสมทุกชนิดจะช้าลงอย่างเห็นได้ชัดในตัวของมันเอง ด้วยการแคชฉลาด


1
ปัญหาที่ควรแก้ไขได้อย่างง่ายดายด้วยฐานข้อมูล SQL
Robert Harvey

1
จากคำอธิบายเพิ่มเติมของคุณนี่เป็นปัญหาระดับ Orbitz เครื่องมือค้นหาของ Orbitz ใช้เครื่องมือ Lisp ที่เลื่อนผ่านจุดข้อมูลหนึ่งพันล้านจุดเพื่อรับรายการเที่ยวบินที่เหมาะสำหรับกำหนดการเดินทางของคุณ มันเป็นข้อกำหนดที่ไม่สามารถใช้งานได้ซึ่งจะต้องส่งคืนโซลูชั่นภายใน 10 วินาทีหรือน้อยกว่า ดูที่นี่paulgraham.com/carl.htmlแต่โปรดทราบว่าข้อมูลค่อนข้างเก่า
Robert Harvey

คำถามนี้ค่อนข้างกว้างและมีสองส่วน: โครงสร้างข้อมูลและอัลกอริทึมสำหรับการค้นหาสูตรอาหารที่มีอยู่ซึ่งเป็นส่วนย่อยของส่วนผสมและวิธีการปรับขนาดสำหรับข้อมูลขนาดใหญ่ สิ่งที่ฉันควรทำคือเป็นสองคำถาม คุณไม่สามารถระบุส่วนข้อมูลขนาดใหญ่ได้จนกว่าคุณจะ จำกัด ส่วนอัลกอริทึมให้แคบลง user16054 ได้รับความช่วยเหลือเกี่ยวกับวิธีใช้ตารางการเข้าร่วมในการแสดงฐานข้อมูลเชิงสัมพันธ์ หากคำถามนี้ถูก จำกัด ให้แคบลงไปยังส่วนอัลกอริทึม / โครงสร้างข้อมูลหรือถามคำถามอิสระอื่นฉันอาจให้คำแนะนำได้
ร็อคกี้

คำตอบ:


4

สำหรับตัวเลขที่คุณให้มาเพียงแค่กำลังดุร้าย

นี่คือโปรแกรมจาวาสคริปต์ที่เดรัจฉานบังคับให้ 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 ส่วนผสมใน DB, 1,000,000 สูตรใน DB, 50 ส่วนผสมต่อสูตรและ 100 ส่วนผสมให้ฉัน นั่นคือค่าที่เท่ากันหรือมากกว่ากรณีที่คุณใช้มากที่สุด

มันทำงานใน 125 มิลลิวินาทีภายใต้ nodejs และนี่คือการใช้งานที่โง่ที่สุดโดยไม่ต้องพยายามปรับให้เหมาะสม


1
เว้นแต่ความต้องการของ OP จะเปลี่ยนไปไม่มีเหตุผลใดที่จะไม่ใช้วิธีการนี้ โครงสร้างข้อมูลที่ชาญฉลาด? ไม่เร็วพอใช่ไหม ใช่. บำรุงรักษาและเข้าใจง่าย แน่นอนที่สุด
J Trana
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.