นี่เป็นหนึ่งในโครงการวิจัยที่ฉันกำลังดำเนินการอยู่ ความต้องการเกือบจะเหมือนกับของคุณและเราได้พัฒนาอัลกอริทึมที่ดีเพื่อแก้ปัญหา
อินพุต
อินพุตเป็นคำหรือวลีภาษาอังกฤษที่ไม่สิ้นสุด (เราเรียกพวกเขาว่า tokens
)
ผลลัพธ์
- ส่งออกโทเค็น N อันดับต้น ๆ ที่เราเคยเห็น (จากโทเค็นทั้งหมดที่เราเห็น!)
- แสดงโทเค็น 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
สัญชาตญาณคือหลังจากนั้นไม่นานจำนวนของการแทรกจะเล็กลงเรื่อย ๆ การดำเนินการมากขึ้นเรื่อย ๆ จะอยู่ในการอัปเดตเท่านั้น และการอัปเดตนี้จะไม่ถูกลงโทษโดยดัชนี
หวังว่าคำอธิบายทั้งหมดนี้จะช่วยได้ :)
what is the most frequent item in the subsequence [2; 2; 3; 3; 3; 4; 4; 4; 4; 5; 5] of your sequence?