อัลกอริทึมเพื่อค้นหาคำค้นหา 10 อันดับแรก


115

ตอนนี้ฉันกำลังเตรียมตัวสำหรับการสัมภาษณ์และมันทำให้ฉันนึกถึงคำถามที่ฉันเคยถามในการสัมภาษณ์ครั้งก่อนที่มีอะไรทำนองนี้:

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

(i) แสดงคำค้นหา 10 อันดับแรกตลอดกาล (เช่นตั้งแต่คุณเริ่มอ่านฟีด)

(ii) แสดงเฉพาะคำค้นหา 10 อันดับแรกของเดือนที่ผ่านมาอัปเดตทุกชั่วโมง

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

ส่วนแรกขอ 10 รายการที่พบบ่อยที่สุดในลำดับย่อยที่เติบโตอย่างต่อเนื่องของรายการที่ไม่มีที่สิ้นสุด ฉันตรวจสอบอัลกอริทึมการเลือก แต่ไม่พบเวอร์ชันออนไลน์ที่จะแก้ปัญหานี้ได้

ส่วนที่สองใช้รายการ จำกัด แต่เนื่องจากมีการประมวลผลข้อมูลจำนวนมากคุณจึงไม่สามารถจัดเก็บข้อความค้นหาทั้งเดือนไว้ในหน่วยความจำและคำนวณฮิสโตแกรมทุกชั่วโมงได้

ปัญหานี้ยากขึ้นเนื่องจากรายชื่อ 10 อันดับแรกกำลังได้รับการอัปเดตอย่างต่อเนื่องดังนั้นคุณต้องคำนวณ 10 อันดับแรกของคุณผ่านหน้าต่างบานเลื่อน

ความคิดใด ๆ ?


11
@BlueRaja - ไม่ใช่คำถามสัมภาษณ์โง่ ๆ แต่เป็นการตีความที่ไม่ดีในส่วนของ OP ไม่ได้ขอรายการที่พบบ่อยที่สุดในรายการที่ไม่มีที่สิ้นสุด แต่จะขอรายการที่พบบ่อยที่สุดในลำดับต่อมาของรายการที่ไม่มีที่สิ้นสุด เพื่อดำเนินการเปรียบเทียบของคุณต่อไปwhat is the most frequent item in the subsequence [2; 2; 3; 3; 3; 4; 4; 4; 4; 5; 5] of your sequence?
IVlad

3
@BlueRaja - แน่นอนว่าเป็นคำถามที่ยาก แต่ฉันไม่เห็นว่าทำไมมันถึงโง่ - ดูเหมือนว่าเป็นตัวแทนของปัญหาทั่วไปที่ บริษัท ที่มีชุดข้อมูลขนาดใหญ่ต้องเผชิญ @IVlad - แก้ไขตามคำแนะนำของคุณถ้อยคำที่ไม่ดีในส่วนของฉัน!
เดล

คำตอบ:


47

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

หนังสือที่มีประโยชน์ในด้านนี้: Muthukrishnan - "Data Streams: Algorithms and Applications"

การอ้างอิงที่เกี่ยวข้องอย่างใกล้ชิดกับปัญหาที่ฉันเลือกจากข้างต้น: Manku, Motwani - "จำนวนความถี่โดยประมาณในสตรีมข้อมูล" [pdf]

อย่างไรก็ตาม Motwani จาก Stanford (แก้ไข) เป็นผู้เขียนหนังสือ"Randomized Algorithms" ที่สำคัญมาก บทที่ 11 ของหนังสือเล่มนี้เกี่ยวข้องกับปัญหานี้ แก้ไข:ขออภัยการอ้างอิงไม่ถูกต้องบทนั้นมีปัญหาอื่น หลังจากตรวจสอบแล้วฉันขอแนะนำส่วน 5.1.2 ของหนังสือของ Muthukrishnanซึ่งมีให้ทางออนไลน์แทน

คำถามสัมภาษณ์ที่ดี


2
+1 สิ่งที่น่าสนใจมากควรมีวิธีบนไซต์ในการแท็กเนื้อหา "เพื่ออ่าน" ขอบคุณสำหรับการแบ่งปัน.
Ramadheer Singh

@ กอลลัม: ฉันมีโฟลเดอร์เพื่ออ่านในบุ๊คมาร์คของฉัน คุณก็ทำได้ ฉันรู้ว่าลิงก์เหล่านั้นกำลังถูกเพิ่มในของฉัน :)
แคม

+1 อัลกอริทึมการสตรีมเป็นหัวข้อที่นี่และหนังสือของ Muthu (หนังสือเล่มเดียวที่เขียนถึงตอนนี้ AFAIK) ก็ยอดเยี่ยม
ShreevatsaR

1
+1 ที่เกี่ยวข้อง: en.wikipedia.org/wiki/Online_algorithm BTW, Motwani เสียชีวิตเมื่อเร็ว ๆ นี้ดังนั้นบางทีเป็นผู้เขียนมีความถูกต้องมากขึ้น

ที่แปลกมาก. ฉันรู้จักเขาจากหนังสือเล่มนี้ แต่เขาต้องมีชื่อเสียงมากกว่านี้แน่นอน: "Motwani เป็นหนึ่งในผู้เขียนร่วม (ร่วมกับแลร์รีเพจและเซอร์เกย์บรินและเทอร์รีวิโนกราด) ของบทความแรกที่มีอิทธิพลในอัลกอริทึม PageRank พื้นฐานสำหรับเทคนิคการค้นหาของ Google "( en.wikipedia.org/wiki/Rajeev_Motwani )
Dimitris Andreou

55

ภาพรวมการประมาณความถี่

มีอัลกอริทึมที่รู้จักกันดีบางอย่างที่สามารถให้ค่าประมาณความถี่สำหรับสตรีมดังกล่าวโดยใช้พื้นที่เก็บข้อมูลคงที่ หนึ่งคือบ่อยโดย Misra and Gries (1982) จากรายการnรายการจะพบรายการทั้งหมดที่เกิดขึ้นมากกว่าn / kครั้งโดยใช้ตัวนับk - 1 นี่คือลักษณะทั่วไปของอัลกอริธึมMajorityของ Boyer and Moore (Fischer-Salzberg, 1982) โดยที่kคือ 2. LossyCountingของ Manku และ Motwani (2002) และSpaceSavingของ Metwallyอัลกอริทึม (2005)มีข้อกำหนดเกี่ยวกับพื้นที่ที่คล้ายคลึงกัน แต่สามารถให้การประมาณที่แม่นยำยิ่งขึ้นภายใต้บางอย่าง เงื่อนไข

สิ่งสำคัญที่ต้องจำไว้คืออัลกอริทึมเหล่านี้สามารถให้ค่าประมาณความถี่เท่านั้น โดยเฉพาะอย่างยิ่งค่าประมาณของ Misra-Gries สามารถนับความถี่จริงได้ต่ำกว่า(n / k)รายการ

สมมติว่าคุณมีอัลกอริทึมที่บวกสามารถระบุรายการเป็นนักเพียง แต่ถ้ามันเกิดขึ้นมากกว่า 50% ของเวลา ฟีดอัลกอริทึมนี้สตรีมของรายการที่แตกต่างกันNรายการจากนั้นเพิ่มอีกN - 1สำเนาของรายการหนึ่งรายการxรวมเป็น2N - 1รายการ หากอัลกอริทึมบอกคุณว่าxเกิน 50% ของทั้งหมดแสดงว่าต้องอยู่ในสตรีมแรก ถ้าไม่แสดงว่าxไม่อยู่ในสตรีมเริ่มต้น เพื่อให้อัลกอริทึมทำการตัดสินใจนี้จะต้องจัดเก็บสตรีมเริ่มต้น (หรือสัดส่วนสรุปบางส่วนตามความยาว)! ดังนั้นเราสามารถพิสูจน์ตัวเองได้ว่าพื้นที่ที่ต้องการโดยอัลกอริทึม "ที่แน่นอน" นั้นจะเป็นΩ ( N )

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

อัลกอริทึมที่ใช้บ่อย

นี่คือคำอธิบายง่ายๆของอัลกอริทึมความถี่ของ Misra-Gries Demaine (2002) และคนอื่น ๆ ได้ปรับอัลกอริทึมให้เหมาะสม แต่สิ่งนี้จะช่วยให้คุณมีส่วนสำคัญ

ระบุเศษส่วนเกณฑ์1 / k ; จะพบรายการใด ๆ ที่เกิดขึ้นมากกว่าn / kครั้ง สร้างแผนที่ว่างเปล่า (เช่นต้นไม้สีแดง - ดำ); คีย์จะเป็นข้อความค้นหาและค่าจะเป็นตัวนับสำหรับคำนั้น

  1. ดูแต่ละรายการในสตรีม
  2. หากมีคำศัพท์อยู่ในแผนที่ให้เพิ่มตัวนับที่เกี่ยวข้อง
  3. มิฉะนั้นหากแผนที่น้อยกว่าk - 1รายการให้เพิ่มคำลงในแผนที่ด้วยตัวนับหนึ่ง
  4. อย่างไรก็ตามหากแผนที่มีรายการk - 1อยู่แล้วให้ลดตัวนับในทุกรายการ หากตัวนับใด ๆ ถึงศูนย์ในระหว่างกระบวนการนี้ให้นำตัวนับออกจากแผนที่

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

การนับการค้นหา

ในบริบทนี้คุณอาจบัฟเฟอร์การค้นหาหนึ่งชั่วโมงและดำเนินการตามขั้นตอนนี้กับข้อมูลของชั่วโมงนั้น หากคุณสามารถใช้เวลาผ่านไปครั้งที่สองในบันทึกการค้นหาของชั่วโมงนี้คุณจะได้รับจำนวนครั้งที่แน่นอนของ "ผู้สมัคร" อันดับต้น ๆ ที่ระบุไว้ในบัตรแรก หรืออาจจะเป็นเรื่องปกติที่จะทำใบเดียวและรายงานผู้สมัครทั้งหมดโดยรู้ว่ารายการใด ๆ ที่ควรมีในนั้นและสิ่งพิเศษใด ๆ เป็นเพียงเสียงรบกวนที่จะหายไปในชั่วโมงถัดไป

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


ฉันเชื่อว่าโซลูชันนี้สามารถทำหน้าที่เป็นตัวกรองและลดจำนวนข้อความค้นหาที่คุณสนใจ หากมีคำใด ๆ เข้ามาในแผนที่ให้เริ่มติดตามสถิติจริงแม้ว่าจะหลุดออกจากแผนที่ก็ตาม จากนั้นคุณสามารถข้ามการส่งผ่านข้อมูลครั้งที่สองและสร้าง10 อันดับแรกที่เรียงลำดับจากสถิติที่ จำกัด ที่คุณรวบรวมได้
Dolph

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

1
@del - โปรดทราบว่าอัลกอริทึมนี้มีไว้สำหรับค้นหาคำศัพท์ที่เกินความถี่เกณฑ์ที่กำหนดซึ่งไม่จำเป็นสำหรับการค้นหาคำศัพท์ทั่วไป หากคำที่พบบ่อยที่สุดต่ำกว่าเกณฑ์ที่กำหนดโดยทั่วไปจะไม่พบคำเหล่านี้ ความกังวลของคุณเกี่ยวกับการลบคำที่ใหม่กว่า "เร็วเกินไป" อาจเกี่ยวข้องกับกรณีนี้ วิธีหนึ่งในการดูสิ่งนี้คือมี "สัญญาณ" ที่เป็นที่นิยมจริงซึ่งจะโดดเด่นอย่างเห็นได้ชัดจาก "สัญญาณรบกวน" แต่บางครั้งไม่พบสัญญาณใด ๆ เพียงแค่ค้นหาแบบสุ่มแบบคงที่
erickson

@erickson - ใช่ - สิ่งที่ฉันได้รับคือสมมติฐานของอัลกอริทึมนี้คือคำ 10 อันดับแรกที่กระจายอยู่ในหน้าต่างการวัดผลอย่างสม่ำเสมอ แต่ตราบใดที่คุณรักษาหน้าต่างการวัดให้เล็กพอ (เช่น 1 ชั่วโมง) นี่อาจเป็นข้อสันนิษฐานที่ถูกต้อง
เดล

1
@erickson ในขณะที่การกระจายแบบสม่ำเสมอไม่ใช่ข้อกำหนด แต่ฉันสงสัยว่าสิ่งนี้จะทำงานอย่างไรในการกระจายที่สมจริงยิ่งขึ้น (กฎหมายอำนาจ, Zipf) สมมติว่าเรามี N คำที่แตกต่างกันและเก็บต้นไม้สีแดงดำของความจุ K ไว้หวังว่ามันจะจบลงด้วยคำที่ใช้บ่อยที่สุด K หากความถี่สะสมของคำศัพท์ (N - K) มีขนาดใหญ่กว่าความถี่สะสมของคำที่ใช้บ่อยที่สุด K ต้นไม้ในท้ายที่สุดจะมีขยะ คุณเห็นด้วยไหม?
Dimitris Andreou

19

นี่เป็นหนึ่งในโครงการวิจัยที่ฉันกำลังดำเนินการอยู่ ความต้องการเกือบจะเหมือนกับของคุณและเราได้พัฒนาอัลกอริทึมที่ดีเพื่อแก้ปัญหา

อินพุต

อินพุตเป็นคำหรือวลีภาษาอังกฤษที่ไม่สิ้นสุด (เราเรียกพวกเขาว่า tokens )

ผลลัพธ์

  1. ส่งออกโทเค็น N อันดับต้น ๆ ที่เราเคยเห็น (จากโทเค็นทั้งหมดที่เราเห็น!)
  2. แสดงโทเค็น N อันดับต้น ๆ ในหน้าต่างประวัติเช่นวันที่แล้วหรือสัปดาห์ที่แล้ว

การประยุกต์ใช้งานวิจัยนี้เพื่อค้นหาประเด็นร้อนหรือแนวโน้มของหัวข้อใน Twitter หรือ Facebook เรามีโปรแกรมรวบรวมข้อมูลที่รวบรวมข้อมูลบนเว็บไซต์ซึ่งสร้างกระแสของคำซึ่งจะป้อนเข้าสู่ระบบ จากนั้นระบบจะแสดงคำหรือวลีที่มีความถี่สูงสุดโดยรวมหรือในอดีต ลองนึกภาพในช่วงสองสามสัปดาห์ที่ผ่านมาวลี "ฟุตบอลโลก" จะปรากฏหลายครั้งในทวิตเตอร์ "พอลปลาหมึก" ก็เช่นกัน :)

สตริงเป็นจำนวนเต็ม

ระบบมี ID จำนวนเต็มสำหรับแต่ละคำ แม้ว่าจะมีคำที่เป็นไปได้แทบจะไม่มีที่สิ้นสุดบนอินเทอร์เน็ต แต่หลังจากสะสมคำจำนวนมากแล้วความเป็นไปได้ในการค้นหาคำศัพท์ใหม่จะลดลงและต่ำลง เราพบคำที่แตกต่างกัน 4 ล้านคำและกำหนดรหัสที่ไม่ซ้ำกันสำหรับแต่ละคำ ชุดข้อมูลทั้งหมดนี้สามารถโหลดลงในหน่วยความจำเป็นตารางแฮชโดยใช้หน่วยความจำประมาณ 300MB (เราได้ใช้ตารางแฮชของเราเองการใช้งาน Java ใช้หน่วยความจำมากเกินไป)

จากนั้นแต่ละวลีสามารถระบุได้ว่าเป็นอาร์เรย์ของจำนวนเต็ม

นี่เป็นสิ่งสำคัญเนื่องจากการเรียงลำดับและการเปรียบเทียบกับจำนวนเต็มนั้นเร็วกว่าสตริงมาก

เก็บข้อมูล

ระบบจะเก็บข้อมูลถาวรสำหรับทุกโทเค็น โดยทั่วไปมันเป็นคู่ของ(Token, Frequency). อย่างไรก็ตามตารางที่เก็บข้อมูลจะมีขนาดใหญ่มากจนเราต้องแบ่งตารางทางกายภาพ เมื่อโครงร่างพาร์ติชันขึ้นอยู่กับ ngrams ของโทเค็น ถ้าโทเค็นเป็นคำเดียวก็คือ 1gram หากโทเค็นเป็นวลีสองคำจะเป็น 2gram และสิ่งนี้จะดำเนินต่อไป โดยประมาณที่ 4gram เรามีบันทึก 1 พันล้านรายการโดยมีขนาดโต๊ะประมาณ 60GB

กำลังประมวลผลสตรีมขาเข้า

ระบบจะดูดซับประโยคที่เข้ามาจนกว่าหน่วยความจำจะถูกใช้อย่างเต็มที่ (เราต้องมี MemoryManager) หลังจากใช้ N ประโยคและจัดเก็บในหน่วยความจำระบบจะหยุดชั่วคราวและเริ่มโทเค็นแต่ละประโยคเป็นคำและวลี แต่ละโทเค็น (คำหรือวลี) จะถูกนับ

สำหรับโทเค็นที่ใช้บ่อยจะถูกเก็บไว้ในความทรงจำเสมอ สำหรับโทเค็นที่ใช้บ่อยน้อยกว่านั้นจะถูกจัดเรียงตาม ID (อย่าลืมว่าเราแปลสตริงเป็นอาร์เรย์ของจำนวนเต็ม) และจัดลำดับลงในไฟล์ดิสก์

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

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

ตอนท้ายของวัน

ในตอนท้ายของวันระบบจะมีโทเค็นที่ใช้บ่อยจำนวนมากพร้อมความถี่ที่จัดเก็บไว้ในหน่วยความจำและโทเค็นที่ใช้บ่อยน้อยกว่าจำนวนมากที่เก็บไว้ในไฟล์ดิสก์หลายไฟล์ (และแต่ละไฟล์จะถูกจัดเรียง)

ระบบจะล้างแม็พในหน่วยความจำลงในไฟล์ดิสก์ (เรียงลำดับ) ตอนนี้ปัญหากลายเป็นการรวมชุดไฟล์ดิสก์ที่เรียงลำดับ เมื่อใช้กระบวนการที่คล้ายกันเราจะได้ไฟล์ดิสก์ที่เรียงลำดับหนึ่งไฟล์ในตอนท้าย

จากนั้นงานสุดท้ายคือการรวมไฟล์ดิสก์ที่เรียงลำดับไว้ในฐานข้อมูลที่เก็บถาวร ขึ้นอยู่กับขนาดของฐานข้อมูลที่เก็บถาวรอัลกอริทึมจะทำงานเหมือนด้านล่างหากมีขนาดใหญ่พอ:

   for each record in sorted disk file
        update archive database by increasing frequency
        if rowcount == 0 then put the record into a list
   end for

   for each record in the list of having rowcount == 0
        insert into archive database
   end for

สัญชาตญาณคือหลังจากนั้นไม่นานจำนวนของการแทรกจะเล็กลงเรื่อย ๆ การดำเนินการมากขึ้นเรื่อย ๆ จะอยู่ในการอัปเดตเท่านั้น และการอัปเดตนี้จะไม่ถูกลงโทษโดยดัชนี

หวังว่าคำอธิบายทั้งหมดนี้จะช่วยได้ :)


ฉันไม่เข้าใจ การเรียงลำดับหรือการเปรียบเทียบที่มีความหมายแบบใดที่สามารถทำได้ใน ID จำนวนเต็มของคำ ไม่ใช่ตัวเลขโดยพลการ?
Dimitris Andreou

นอกจากนี้การนับความถี่ของคำยังเป็นตัวอย่างแรกในกระดาษ MapReduce ของ Google ( labs.google.com/papers/mapreduce.html ) ซึ่งจะแก้ปัญหาได้ในไม่กี่บรรทัด คุณสามารถย้ายข้อมูลของคุณไปยังแอป Google angine และทำ MapReduce ( code.google.com/p/appengine-mapreduce )
Dimitris Andreou

@Dimitris Andreou: การเรียงลำดับจำนวนเต็มจะเร็วกว่าในสตริง เนื่องจากการเปรียบเทียบจำนวนเต็มสองจำนวนนั้นเร็วกว่าการเปรียบเทียบสองสตริง
SiLent SoNG

@Dimitris Andreou: mapreduce ของ Google เป็นแนวทางการกระจายที่ดีในการแก้ปัญหานี้ อา! ขอบคุณที่ให้ลิงค์ ใช่มันจะเป็นการดีที่เราจะจัดเรียงโดยใช้หลายเครื่อง แนวทางที่ดี
SiLent SoNG

@Dimitris Andreou: จนถึงตอนนี้ฉันได้พิจารณาวิธีการเรียงลำดับด้วยเครื่องเดียวเท่านั้น ช่างเป็นความคิดที่ดีที่จะจัดเรียงในการแจกจ่าย
SiLent SoNG

4

คุณสามารถใช้ตารางแฮชรวมกับต้นไม้ค้นหาแบบทวิภาค ใช้<search term, count>พจนานุกรมที่บอกจำนวนครั้งที่มีการค้นหาคำค้นหาแต่ละคำ

เห็นได้ชัดว่าการทำซ้ำตารางแฮชทั้งหมดทุก ๆ ชั่วโมงเพื่อให้ได้ 10 อันดับแรกนั้นแย่มาก แต่นี่คือ Google ที่เรากำลังพูดถึงดังนั้นคุณสามารถสันนิษฐานได้ว่าหนึ่งในสิบอันดับแรกจะได้รับทั้งหมดพูดได้มากกว่า 10,000 ครั้ง (อาจเป็นจำนวนที่มากกว่า) ดังนั้นทุกครั้งที่จำนวนข้อความค้นหาเกิน 10,000 ให้ใส่ใน BST จากนั้นทุกชั่วโมงคุณจะต้องได้รับ 10 อันดับแรกจาก BST ซึ่งควรมีรายการค่อนข้างน้อย

วิธีนี้ช่วยแก้ปัญหา 10 อันดับแรกของเวลาทั้งหมด


ส่วนที่ยุ่งยากจริงๆคือการจัดการกับคำศัพท์หนึ่งที่เข้ามาแทนที่อีกคำหนึ่งในรายงานประจำเดือน (เช่น "stack overflow" อาจมีการเข้าชม 50,000 ครั้งในช่วงสองเดือนที่ผ่านมา แต่มีเพียง 10,000 ครั้งในเดือนที่ผ่านมาในขณะที่ "amazon" อาจมี 40 000 สำหรับสองเดือนที่ผ่านมา แต่ 30,000 สำหรับเดือนที่ผ่านมาคุณต้องการให้ "amazon" อยู่ก่อน "stack overflow" ในรายงานประจำเดือนของคุณ) ในการดำเนินการนี้ฉันจะจัดเก็บคำค้นหาหลักทั้งหมด (มากกว่า 10,000 ครั้งที่มีการค้นหาตลอดเวลา) รายการ 30 วันที่บอกคุณว่ามีการค้นหาคำนั้นกี่ครั้งในแต่ละวัน รายการจะทำงานเหมือนคิว FIFO: คุณลบวันแรกและแทรกวันใหม่ในแต่ละวัน (หรือในแต่ละชั่วโมง แต่คุณอาจต้องเก็บข้อมูลเพิ่มเติมซึ่งหมายถึงหน่วยความจำ / พื้นที่มากขึ้นหากหน่วยความจำไม่ใช่ปัญหาให้ทำ มิฉะนั้นให้ไปที่ "การประมาณ"

นี่ดูเหมือนเป็นการเริ่มต้นที่ดี จากนั้นคุณสามารถกังวลเกี่ยวกับการตัดคำที่มีมากกว่า 10,000 ครั้ง แต่ไม่ได้มีจำนวนมากมานานแล้วและสิ่งต่างๆเช่นนั้น


3

กรณีที่ฉัน)

รักษาแฮชแท็กสำหรับโปรแกรมค้นหาทั้งหมดรวมถึงรายการสิบอันดับแรกที่เรียงลำดับแยกต่างหากจากแฮชแท็ก เมื่อใดก็ตามที่เกิดการค้นหาให้เพิ่มรายการที่เหมาะสมในแฮชแท็กและตรวจสอบว่าตอนนี้ควรเปลี่ยนรายการนั้นกับรายการที่ 10 ในรายการสิบอันดับแรกหรือไม่

O (1) ค้นหารายการสิบอันดับแรกและการแทรกสูงสุด O (log (n)) ในแฮชแท็ก (สมมติว่าการชนกันที่จัดการโดยต้นไม้ไบนารีที่ปรับสมดุลในตัวเอง)

กรณีที่ ii) แทนที่จะรักษาแฮชแท็กขนาดใหญ่และรายการเล็ก ๆ เรายังคงรักษาแฮชแท็กและรายการที่เรียงลำดับของรายการทั้งหมด เมื่อใดก็ตามที่มีการค้นหาคำนั้นจะเพิ่มขึ้นในแฮชแท็กและในรายการที่เรียงลำดับจะสามารถตรวจสอบคำศัพท์เพื่อดูว่าควรสลับกับคำที่ตามมาหรือไม่ ต้นไม้ไบนารีที่ปรับสมดุลในตัวเองสามารถทำงานได้ดีเนื่องจากเราต้องสามารถสืบค้นได้อย่างรวดเร็ว (เพิ่มเติมในภายหลัง)

นอกจากนี้เรายังมีรายการ 'ชั่วโมง' ในรูปแบบของรายการ FIFO (คิว) องค์ประกอบ "ชั่วโมง" แต่ละรายการจะมีรายการการค้นหาทั้งหมดที่เกิดขึ้นภายในชั่วโมงนั้น ๆ ตัวอย่างเช่นรายการชั่วโมงของเราอาจมีลักษณะดังนี้:

Time: 0 hours
      -Search Terms:
          -free stuff: 56
          -funny pics: 321
          -stackoverflow: 1234
Time: 1 hour
      -Search Terms:
          -ebay: 12
          -funny pics: 1
          -stackoverflow: 522
          -BP sucks: 92

จากนั้นทุกชั่วโมง: หากรายการมีความยาวอย่างน้อย 720 ชั่วโมง (นั่นคือจำนวนชั่วโมงใน 30 วัน) ให้ดูองค์ประกอบแรกในรายการและสำหรับแต่ละคำค้นหาให้ลดองค์ประกอบนั้นในแฮชแท็กตามจำนวนที่เหมาะสม . หลังจากนั้นให้ลบองค์ประกอบของชั่วโมงแรกนั้นออกจากรายการ

สมมติว่าเราอยู่ที่ชั่วโมง 721 และเราพร้อมที่จะดูชั่วโมงแรกในรายการ (ด้านบน) เราจะลดของฟรีลง 56 ในแฮชแท็กรูปตลกโดย 321 เป็นต้นจากนั้นจะลบชั่วโมง 0 ออกจากรายการทั้งหมดเนื่องจากเราจะไม่ต้องดูมันอีก

เหตุผลที่เรายังคงจัดเรียงรายการคำศัพท์ทั้งหมดที่ช่วยให้สามารถค้นหาได้อย่างรวดเร็วเนื่องจากทุก ๆ ชั่วโมงหลังจากที่เราอ่านข้อความค้นหาตั้งแต่ 720 ชั่วโมงที่ผ่านมาเราจำเป็นต้องตรวจสอบให้แน่ใจว่ารายการสิบอันดับแรกยังคงถูกจัดเรียงอยู่ ดังนั้นเมื่อเราลด 'ของฟรี' ลง 56 ในแฮชแท็กเราจะตรวจสอบว่าตอนนี้อยู่ที่ไหนในรายการ เนื่องจากเป็นต้นไม้ไบนารีที่ปรับสมดุลในตัวเองทั้งหมดนี้สามารถทำได้อย่างดีในเวลา O (log (n))


แก้ไข: เสียสละความถูกต้องเพื่อพื้นที่ ...

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


2

คิดคร่าวๆ ...

ติดท็อป 10 ตลอดกาล

  • การใช้คอลเลกชันแฮชที่มีการจัดเก็บจำนวนสำหรับแต่ละคำ (ล้างเงื่อนไข ฯลฯ )
  • อาร์เรย์ที่เรียงลำดับซึ่งมี 10 อันดับแรกที่ต่อเนื่องคำ / จำนวนในที่เพิ่มเข้าไปในอาร์เรย์นี้เมื่อใดก็ตามที่จำนวนของคำมีค่าเท่ากับหรือมากกว่าจำนวนที่น้อยที่สุดในอาร์เรย์

สำหรับรายเดือน 10 อันดับแรกที่อัปเดตทุกชั่วโมง:

  • การใช้อาร์เรย์ที่จัดทำดัชนีตามจำนวนชั่วโมงที่ผ่านไปนับตั้งแต่เริ่มโมดูโล 744 (จำนวนชั่วโมงในหนึ่งเดือน) ซึ่งรายการอาร์เรย์ประกอบด้วยการรวบรวมแฮชที่มีการจัดเก็บจำนวนสำหรับแต่ละคำที่พบในช่วงช่องชั่วโมงนี้ รายการจะถูกรีเซ็ตทุกครั้งที่ตัวนับช่องชั่วโมงเปลี่ยนแปลง
  • สถิติในอาร์เรย์ที่จัดทำดัชนีในช่องชั่วโมงจะต้องถูกรวบรวมเมื่อใดก็ตามที่ตัวนับช่องชั่วโมงปัจจุบันเปลี่ยนไป (สูงสุดชั่วโมงละครั้ง) โดยการคัดลอกและทำให้แบนเนื้อหาของอาร์เรย์นี้ที่ทำดัชนีในช่องชั่วโมง

เอ่อ ... เข้าท่ามั้ย? ฉันไม่คิดว่าสิ่งนี้จะผ่านไปในชีวิตจริง

อ๊ะใช่ลืมพูดถึง "การคัดลอก / การแบน" รายชั่วโมงที่จำเป็นสำหรับสถิติรายเดือนสามารถนำรหัสเดิมที่ใช้กับ 10 อันดับแรกของเวลากลับมาใช้ใหม่ได้ซึ่งเป็นผลข้างเคียงที่ดี


2

โซลูชันที่แน่นอน

ประการแรกโซลูชันที่รับประกันผลลัพธ์ที่ถูกต้อง แต่ต้องใช้หน่วยความจำจำนวนมาก (แผนที่ขนาดใหญ่)

ตัวแปร "ตลอดเวลา"

ดูแลแฮชแมปที่มีคิวรีเป็นคีย์และนับเป็นค่า นอกจากนี้ให้เก็บรายการ f 10 คำถามที่พบบ่อยที่สุดและจำนวนการนับที่พบบ่อยที่สุดอันดับที่ 10 (เกณฑ์)

อัปเดตแผนที่อย่างต่อเนื่องเมื่อมีการอ่านกระแสการสืบค้น ทุกครั้งที่มีการนับเกินเกณฑ์ปัจจุบันให้ทำดังต่อไปนี้: ลบคำค้นหาที่ 10 ออกจากรายการ "10 อันดับแรก" แทนที่ด้วยข้อความค้นหาที่คุณเพิ่งอัปเดตและอัปเดตเกณฑ์ด้วย

ตัวแปร "เดือนที่ผ่านมา"

เก็บรายการ "10 อันดับแรก" เดิมไว้และอัปเดตแบบเดียวกับด้านบน นอกจากนี้ให้เก็บแผนที่ที่คล้ายกัน แต่เวลานี้เก็บเวกเตอร์ที่ 30 * 24 = 720 นับ (หนึ่งสำหรับแต่ละชั่วโมง) เป็นค่า ทุก ๆ ชั่วโมงให้ทำสิ่งต่อไปนี้สำหรับทุกคีย์: ลบตัวนับที่เก่าที่สุดออกจากเวกเตอร์แล้วเพิ่มตัวนับใหม่ (เริ่มต้นเป็น 0) ที่ท้าย ลบคีย์ออกจากแผนที่หากเวกเตอร์เป็นศูนย์ทั้งหมด นอกจากนี้ทุก ๆ ชั่วโมงคุณจะต้องคำนวณรายการ "10 อันดับแรก" ตั้งแต่เริ่มต้น

หมายเหตุ: ใช่คราวนี้เรากำลังจัดเก็บจำนวนเต็ม 720 จำนวนแทนที่จะเป็นหนึ่ง แต่มีคีย์น้อยกว่ามาก (ตัวแปรตลอดเวลามีหางยาวจริงๆ )

ใกล้เคียง

การประมาณเหล่านี้ไม่ได้รับประกันวิธีแก้ปัญหาที่ถูกต้อง แต่ใช้หน่วยความจำน้อยกว่า

  1. ประมวลผลแบบสอบถาม N-th ทุกรายการโดยข้ามส่วนที่เหลือ
  2. (สำหรับตัวแปรตลอดเวลาเท่านั้น) เก็บคู่คีย์ - ค่า M ไว้สูงสุดในแผนที่ (M ควรมีขนาดใหญ่ที่สุดเท่าที่คุณจะจ่ายได้) เป็นแคช LRU ชนิดหนึ่ง: ทุกครั้งที่คุณอ่านข้อความค้นหาที่ไม่ได้อยู่ในแผนที่ให้ลบคำค้นหาที่ใช้ล่าสุดโดยนับ 1 และแทนที่ด้วยแบบสอบถามที่ประมวลผลในปัจจุบัน

ฉันชอบแนวทางความน่าจะเป็นในการประมาณ 1 แต่การใช้การประมาณ 2 (แคช LRU) จะเกิดอะไรขึ้นหากคำศัพท์ที่ไม่ได้รับความนิยมในตอนแรกกลายเป็นที่นิยมในภายหลัง พวกเขาจะไม่ถูกทิ้งทุกครั้งที่มีการเพิ่มเนื่องจากจำนวนของพวกเขาจะต่ำมากหรือไม่?
เดล

@del คุณพูดถูกการประมาณครั้งที่สองจะใช้ได้กับสตรีมคำถามบางอย่างเท่านั้น มีความน่าเชื่อถือน้อยกว่า แต่ในขณะเดียวกันก็ต้องใช้ทรัพยากรน้อยลง หมายเหตุ: คุณยังรวมค่าประมาณทั้งสองได้ด้วย
Bolo

2

คำค้นหา 10 อันดับแรกของเดือนที่ผ่านมา

การใช้การจัดทำดัชนี / โครงสร้างข้อมูลที่มีประสิทธิภาพของหน่วยความจำเช่นการพยายามที่อัดแน่น (จากรายการวิกิพีเดียเมื่อพยายาม ) โดยประมาณจะกำหนดความสัมพันธ์บางอย่างระหว่างข้อกำหนดหน่วยความจำและ n - จำนวนคำศัพท์

ในกรณีที่มีหน่วยความจำที่ต้องการ ( สมมติฐานที่ 1 ) คุณสามารถเก็บสถิติรายเดือนที่แน่นอนและรวมทุกเดือนเป็นสถิติเวลาทั้งหมด

นอกจากนี้ยังมีข้อสันนิษฐานที่ตีความ 'เดือนที่แล้ว' เป็นหน้าต่างคงที่ แต่แม้ว่าหน้าต่างรายเดือนจะเลื่อนขั้นตอนข้างต้นก็แสดงให้เห็นถึงหลักการ (เลื่อนสามารถประมาณด้วยหน้าต่างคงที่ตามขนาดที่กำหนด)

นี่ทำให้ฉันนึกถึงฐานข้อมูลแบบ Round-Robinโดยมีข้อยกเว้นว่าสถิติบางอย่างถูกคำนวณใน 'all time' (ในแง่ที่ว่าข้อมูลทั้งหมดจะไม่ถูกเก็บไว้ rrd รวมช่วงเวลาโดยไม่คำนึงถึงรายละเอียดโดยการหาค่าเฉลี่ยสรุปหรือเลือกค่าสูงสุด / นาที ในงานที่กำหนดรายละเอียดที่หายไปคือข้อมูลเกี่ยวกับรายการความถี่ต่ำซึ่งอาจทำให้เกิดข้อผิดพลาดได้)

สมมติฐาน 1

หากเราไม่สามารถเก็บสถิติที่สมบูรณ์แบบตลอดทั้งเดือนได้เราควรจะหาช่วงเวลาหนึ่งที่เราควรจะสามารถถือสถิติที่สมบูรณ์แบบได้ ตัวอย่างเช่นสมมติว่าเรามีสถิติที่สมบูรณ์แบบในช่วงเวลาหนึ่ง P ซึ่งจะแบ่งเป็นเดือน n ครั้ง สถิติที่สมบูรณ์แบบกำหนดฟังก์ชั่น
f(search_term) -> search_term_occurance

หากเราสามารถเก็บnตารางสถิติที่สมบูรณ์แบบทั้งหมดไว้ในหน่วยความจำสามารถคำนวณสถิติรายเดือนแบบเลื่อนได้ดังนี้:

  • เพิ่มสถิติสำหรับช่วงเวลาใหม่ล่าสุด
  • ลบสถิติในช่วงเวลาที่เก่าแก่ที่สุด (ดังนั้นเราต้องเก็บnตารางสถิติที่สมบูรณ์แบบไว้)

อย่างไรก็ตามหากเราเก็บเพียง 10 อันดับแรกในระดับรวม (รายเดือน) เราจะสามารถทิ้งข้อมูลจำนวนมากจากสถิติทั้งหมดของช่วงเวลาที่กำหนดได้ สิ่งนี้ให้ขั้นตอนการทำงานที่กำหนดไว้แล้ว (สมมติว่าขอบเขตบนบนตารางสถิติสมบูรณ์แบบสำหรับช่วงเวลา P)

ปัญหาเกี่ยวกับขั้นตอนข้างต้นคือถ้าเราเก็บข้อมูลไว้เฉพาะคำ 10 อันดับแรกสำหรับหน้าต่างบานเลื่อน (ในทำนองเดียวกันตลอดเวลา) สถิติจะถูกต้องสำหรับข้อความค้นหาที่มีจุดสูงสุดในช่วงเวลาหนึ่ง แต่อาจไม่เห็น สถิติของข้อความค้นหาที่ไหลเข้ามาตลอดเวลา

สิ่งนี้สามารถหักล้างได้โดยการเก็บข้อมูลมากกว่า 10 คำศัพท์ที่ดีที่สุดตัวอย่างเช่นคำศัพท์ 100 อันดับแรกหวังว่า 10 อันดับแรกจะถูกต้อง

ฉันคิดว่าการวิเคราะห์เพิ่มเติมอาจเกี่ยวข้องกับจำนวนเหตุการณ์ขั้นต่ำที่จำเป็นสำหรับรายการที่จะกลายเป็นส่วนหนึ่งของสถิติ (ซึ่งเกี่ยวข้องกับข้อผิดพลาดสูงสุด)

(ในการตัดสินใจว่ารายการใดควรเป็นส่วนหนึ่งของสถิติเราสามารถตรวจสอบและติดตามแนวโน้มได้เช่นหากการคาดคะเนเชิงเส้นของเหตุการณ์ที่เกิดขึ้นในแต่ละช่วงเวลา P สำหรับแต่ละคำจะบอกคุณว่าคำนั้นจะมีความสำคัญในหนึ่งหรือสองเดือนคุณ อาจเริ่มติดตามได้แล้วหลักการที่คล้ายกันนี้ใช้สำหรับการลบข้อความค้นหาออกจากกลุ่มที่ติดตาม)

กรณีที่แย่ที่สุดสำหรับข้างต้นคือเมื่อคุณมีคำศัพท์ที่ใช้บ่อยเกือบเท่า ๆ กันและมีการเปลี่ยนแปลงตลอดเวลา (เช่นหากติดตามเพียง 100 คำดังนั้นหากคำศัพท์ 150 อันดับแรกเกิดขึ้นบ่อยเท่า ๆ กัน แต่ 50 อันดับแรกมักจะเกิดขึ้นในเดือนแรกและ เกรงว่าในเวลาต่อมาสถิติจะไม่ถูกเก็บไว้อย่างถูกต้อง)

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


2

แล้วการปรับ"อัลกอริทึมการเปลี่ยนหน้านาฬิกา" (หรือที่เรียกว่า "โอกาสที่สอง") จะเป็นอย่างไร ฉันสามารถจินตนาการได้ว่ามันจะทำงานได้ดีมากหากมีการกระจายคำขอค้นหาอย่างเท่าเทียมกัน (นั่นหมายความว่าข้อความค้นหาส่วนใหญ่จะปรากฏเป็นประจำมากกว่า 5 นาทีติดต่อกันและไม่ปรากฏอีกเลย)

นี่คือการแสดงภาพของอัลกอริทึม: อัลกอริทึมการเปลี่ยนหน้านาฬิกา


0

จัดเก็บจำนวนข้อความค้นหาในตารางแฮชขนาดใหญ่ซึ่งการค้นหาใหม่แต่ละครั้งจะทำให้องค์ประกอบเฉพาะเพิ่มขึ้นทีละรายการ ติดตามคำค้นหา 20 อันดับแรกหรือมากกว่านั้น เมื่อองค์ประกอบในอันดับที่ 11 เพิ่มขึ้นให้ตรวจสอบว่าจำเป็นต้องสลับตำแหน่งกับ # 10 * หรือไม่ (ไม่จำเป็นต้องจัดเรียง 10 อันดับแรกสิ่งที่คุณสนใจคือการวาดความแตกต่างระหว่างวันที่ 10 ถึง 11)

* ต้องมีการตรวจสอบที่คล้ายกันเพื่อดูว่าข้อความค้นหาใหม่อยู่ในอันดับที่ 11 หรือไม่ดังนั้นอัลกอริทึมนี้จึงขยายไปยังข้อความค้นหาอื่น ๆ ด้วยดังนั้นฉันจึงทำให้ง่ายขึ้นเล็กน้อย


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

ฉันค่อนข้างมั่นใจว่า Google มีการนับทุกอย่างแม้ว่าการนับบางรายการจะไม่คงที่ แต่จะคำนวณตามความจำเป็น
Ether

0

บางครั้งคำตอบที่ดีที่สุดคือ "ฉันไม่รู้"

ฉันจะแทงลึกลงไป สัญชาตญาณแรกของฉันคือป้อนผลลัพธ์ให้เป็น Q กระบวนการจะประมวลผลรายการต่างๆที่เข้ามาใน Q อย่างต่อเนื่องกระบวนการนี้จะรักษาแผนที่ของ

ระยะ -> นับ

ทุกครั้งที่ประมวลผลรายการ Q คุณเพียงแค่ค้นหาคำค้นหาและเพิ่มจำนวน

ในขณะเดียวกันฉันจะรักษารายชื่อการอ้างอิงถึง 10 อันดับแรกในแผนที่

สำหรับรายการที่ดำเนินการในปัจจุบันให้ดูว่าจำนวนของรายการนั้นมากกว่าจำนวนรายการที่น้อยที่สุดใน 10 อันดับแรกหรือไม่ (หากยังไม่อยู่ในรายการ) ถ้าเป็นเช่นนั้นให้แทนที่ค่าที่เล็กที่สุดด้วยรายการ

ฉันคิดว่าจะได้ผล ไม่มีการดำเนินการใดที่ต้องใช้เวลามาก คุณจะต้องหาวิธีจัดการขนาดของแผนที่นับ แต่นั่นก็น่าจะดีพอสำหรับคำตอบในการสัมภาษณ์

พวกเขาไม่ได้คาดหวังทางแก้ปัญหาที่ต้องการดูว่าคุณคิดได้ไหม คุณไม่ต้องเขียนวิธีแก้ปัญหาแล้วที่นั่น ....


12
โครงสร้างข้อมูลที่เรียกว่าqueue, Qเป็นตัวอักษร :)
IVlad

3
ถ้าฉันกำลังทำการสัมภาษณ์ "ฉันไม่รู้ว่า <stop>" คงไม่ใช่คำตอบที่ดีที่สุด คิดถึงเท้าของคุณ ถ้าคุณไม่รู้ลองคิดออกหรืออย่างน้อยก็ลองดู
Stephen

ในการสัมภาษณ์เมื่อฉันเห็นคนที่จำศีลใน 7 หน้ากลับมาดำเนินการต่อ 5 ครั้งและพวกเขาไม่สามารถบอกฉันได้ว่า ORM คืออะไรฉันจึงยุติการสัมภาษณ์ทันที Id แต่พวกเขาไม่ได้ใส่ไว้ในประวัติย่อของพวกเขาและพูดว่า: "ฉันไม่รู้" ไม่มีใครรู้ทุกอย่าง @IVIad ฉันแกล้งทำเป็นว่าฉันเป็นนักพัฒนา C และพยายามบันทึกบิต ... ;)
hvgotcodes

0

วิธีหนึ่งคือสำหรับการค้นหาทุกครั้งคุณจะจัดเก็บคำค้นหานั้นและการประทับเวลา ด้วยวิธีนี้การค้นหาสิบอันดับแรกในช่วงเวลาใดก็ได้เป็นเพียงแค่การเปรียบเทียบข้อความค้นหาทั้งหมดภายในช่วงเวลาที่กำหนด

อัลกอริทึมนั้นเรียบง่าย แต่ข้อเสียเปรียบคือหน่วยความจำและการใช้เวลาที่มากขึ้น


0

สิ่งที่เกี่ยวกับการใช้Splay Treeกับ 10 โหนดล่ะ? ทุกครั้งที่คุณพยายามเข้าถึงค่า (ข้อความค้นหา) ที่ไม่มีอยู่ในต้นไม้ให้โยนใบไม้ออกใส่ค่าแทนแล้วเข้าถึง

แนวคิดเบื้องหลังสิ่งนี้เหมือนกับในคำตอบอื่น ๆ ของฉันคำตอบภายใต้สมมติฐานว่ามีการเข้าถึงข้อความค้นหาอย่างสม่ำเสมอ / สม่ำเสมอโซลูชันนี้ควรทำงานได้ดีมาก

แก้ไข

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


0

Dunno ว่าฉันเข้าใจถูกหรือไม่ วิธีแก้ปัญหาของฉันคือการใช้ฮีป เนื่องจากรายการค้นหา 10 อันดับแรกฉันจึงสร้างฮีปที่มีขนาด 10 จากนั้นอัปเดตฮีปนี้ด้วยการค้นหาใหม่ หากความถี่ของการค้นหาใหม่มากกว่าฮีป (Max Heap) ด้านบนให้อัปเดต ละทิ้งอันที่มีความถี่น้อยที่สุด

แต่วิธีคำนวณความถี่ของการค้นหาเฉพาะจะนับเป็นอย่างอื่น อาจจะตามที่ทุกคนระบุอัลกอริทึมสตรีมข้อมูล ....


0

ใช้ cm-sketch เพื่อเก็บจำนวนการค้นหาทั้งหมดตั้งแต่เริ่มต้นเก็บ min-heap ขนาด 10 ไว้สำหรับ top 10 สำหรับผลลัพธ์รายเดือนให้เก็บ 30 cm-sketch / hash-table และ min-heap ไว้ด้วยการเริ่มต้นแต่ละครั้ง นับและอัปเดตล่าสุด 30, 29 .. , 1 วัน เมื่อผ่านไปหนึ่งวันให้ล้างรายการสุดท้ายและใช้เป็นวันที่ 1 เหมือนกันสำหรับผลลัพธ์รายชั่วโมงเก็บ 60 ตารางแฮชและฮีปขั้นต่ำและเริ่มนับในช่วง 60, 59, ... 1 นาทีสุดท้าย เมื่อผ่านไป 1 นาทีให้ล้างค่าสุดท้ายและใช้เป็นนาทีที่ 1

ผลลัพธ์รายเดือนมีความแม่นยำในช่วง 1 วันผลลัพธ์รายชั่วโมงมีความแม่นยำในช่วง 1 นาที


0

ปัญหานี้ไม่สามารถแก้ไขได้ในระดับสากลเมื่อคุณมีหน่วยความจำจำนวนคงที่และกระแสของโทเค็นที่ 'ไม่มีที่สิ้นสุด' (คิดว่าใหญ่มาก)

อธิบายคร่าวๆ ...

หากต้องการดูสาเหตุให้พิจารณาสตรีมโทเค็นที่มีโทเค็นเฉพาะ (เช่นคำ) T ทุกโทเค็น N ในสตรีมอินพุต

นอกจากนี้สมมติว่าหน่วยความจำสามารถเก็บการอ้างอิง (รหัสคำและจำนวน) ไว้ที่โทเค็น M ได้มากที่สุด

ด้วยเงื่อนไขเหล่านี้จึงเป็นไปได้ที่จะสร้างสตรีมอินพุตโดยที่โทเค็น T จะไม่ถูกตรวจพบหาก N มีขนาดใหญ่เพียงพอเพื่อให้สตรีมมีโทเค็น M ที่แตกต่างกันระหว่าง T

สิ่งนี้ไม่ขึ้นอยู่กับรายละเอียดอัลกอริทึม top-N ขึ้นอยู่กับขีด จำกัด M. เท่านั้น

หากต้องการดูว่าเหตุใดจึงเป็นจริงให้พิจารณาสตรีมที่เข้ามาซึ่งประกอบด้วยกลุ่มของโทเค็นที่เหมือนกันสองกลุ่ม:

T a1 a2 a3 ... a-M T b1 b2 b3 ... b-M ...

โดยที่ a และ b เป็นโทเค็นที่ถูกต้องทั้งหมดไม่เท่ากับ T

สังเกตว่าในสตรีมนี้ T จะปรากฏขึ้นสองครั้งสำหรับแต่ละ ai และ bi แต่ดูเหมือนไม่ค่อยเพียงพอที่จะถูกล้างออกจากระบบ

เริ่มต้นด้วยหน่วยความจำว่างโทเค็นแรก (T) จะกินพื้นที่ในหน่วยความจำ (ล้อมรอบด้วย M) จากนั้น a1 จะกินสล็อตไปจนถึง a- (M-1) เมื่อ M หมด

เมื่อ aM มาถึงอัลกอริทึมจะต้องวางสัญลักษณ์หนึ่งตัวเพื่อให้เป็น T สัญลักษณ์ถัดไปจะเป็น b-1 ซึ่งจะทำให้ a-1 ถูกล้างเป็นต้น

ดังนั้น T จะไม่อยู่ในหน่วยความจำนานพอที่จะสร้างจำนวนจริงได้ กล่าวโดยย่อคืออัลกอริทึมใด ๆ จะพลาดโทเค็นที่มีความถี่ท้องถิ่นต่ำเพียงพอ แต่มีความถี่ทั่วโลกสูง (เกินความยาวของสตรีม)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.