ประสิทธิภาพการกรองคำหยาบใน Java


9

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

มีข้อมูลสองบิต:

  1. การส่งของผู้ใช้ซึ่งอาจมี 500 คำหรือมากกว่านั้น
  2. ตารางฐานข้อมูลคอลัมน์เดี่ยวที่มีคำที่ไม่ได้รับอนุญาต อาจมีหลายพันระเบียนในตารางนี้

วิธีแก้ปัญหาปัจจุบันดูเหมือนผิดกับฉัน:

  1. ตารางทั้งหมดจะถูกโหลดลงในสแตติก String [] เมื่อเริ่มต้นเป็น Singleton (ดังนั้นจึงอยู่ในหน่วยความจำ)
  2. สำหรับการส่งผู้ใช้แต่ละครั้งเราวนลูปผ่านอาร์เรย์และทำ. indexOf () เพื่อดูว่ามีคำที่ให้ไว้ใน String [] ปรากฏในการส่งหรือไม่
  3. ถ้ามันปรากฏขึ้นเราจะแทนที่ด้วยตัวอักษรสไตล์% $ # @% สิ่งนี้ทำได้โดยโทเค็นการส่งผู้ใช้วนซ้ำผ่านการส่งผู้ใช้ทั้งหมดเป็นโทเค็น (อีกครั้ง) และแทนที่แต่ละอินสแตนซ์ของคำที่พบ

อาจมีความฉลาดในการแก้ปัญหานี้ แต่ฉันสงสัย และเมื่อได้ดูมันซักพักฉันก็หาทางผ่านไม่ได้

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


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

ฉันคิดว่าวิธีการแก้ปัญหานั้นผิดพลาดหลัก ๆ เพราะรหัสฐานที่ฉันทำงานอยู่นั้นไม่เพียงพอและเลอะเทอะ ด้วยความลำเอียงของฉันฉันไม่เชื่อใจในตัวเอง ฉันรู้สึกว่าความคิดเห็นของผู้อื่นจะเป็นประโยชน์ สิ่งที่ทำให้เกิดการเตือนภัยสำหรับฉันคือ String [] (คืออะไรปี 1999 นี้) วนไปตามสตริงที่มีขนาดใหญ่มากแทนที่จะเป็นชุดข้อมูลขนาดเล็กกว่าที่ผู้ใช้ส่งมาซ้อนวนภายใน String [] ด้วยการส่งผู้ใช้ tokenized และอื่น ๆ การใช้งานที่คาดหวังนั้นไม่ได้ระบุไว้เป็นอย่างดีว่าโซลูชันที่สง่างามพร้อมประสิทธิภาพที่สมเหตุสมผลจะน่ารัก
blueishgoldfish

2
'ประสิทธิภาพที่สมเหตุสมผล' อาจหมายถึงอะไรก็ได้ หากคุณไม่มีเป้าหมายที่เป็นรูปธรรมคุณจะไม่รู้ว่าคุณไปถึงเป้าหมายนั้นหรือไม่ หากคุณเร่งกระบวนการให้เร็วขึ้น 100 เท่านี่เป็นเป้าหมายหรือไม่? หากผู้ใช้กำลังรอ 1ms หรือ 1 / 10s ผู้ใช้จะไม่ได้รับประโยชน์จากการทำงานของคุณ
ผู้ใช้ที่ไม่รู้จัก

คำตอบ:


18

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

มันขึ้นอยู่กับอัลกอริทึมDouble MetaPhoneที่ได้รับการแก้ไขอย่างสูงซึ่งได้รับการปรับแต่งให้มีความแม่นยำมากขึ้นแทนที่จะเป็นค่าเริ่มต้น มันมีประสิทธิภาพอย่างมากเพราะมันเลือกการสะกดผิดและการสะกดคำแบบออกเสียงเหมือนกับคำจริง ฉันได้เพิ่มการl33tพูดและtxtพูดคุยกับอัลกอริทึม MetaPhone ด้วยทำให้เป็นอัลกอริทึม Triple / Quad Metaphone

มันนำเสนอตัวประมวลผลล่วงหน้าที่บีบอัดตัวอักษรวิ่งและตรวจจับสิ่งต่าง ๆ เช่นเด็ก ๆ นำสิ่งต่าง ๆ เช่นw o r d sโดยการบีบอัดตัวอักษรอย่างชาญฉลาดเข้าด้วยกันและกำจัดการทำงานซ้ำซ้อนเช่นwwoorrddssนั้น

มันเร็วพอที่ 8 ปีที่แล้วที่จะใช้ในสตรีมระบบแชทเรียลไทม์โดยไม่มีความล่าช้าแฝงที่เห็นได้ชัดเจนกับผู้ใช้นับหมื่นบนระบบซีพียูแกนเดียว

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

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


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

ดังนั้นฉันเดาว่าครึ่งหนึ่งของผู้คนจะหยุดเล่นเกมตอนนี้: D
Davor Juldralo

2

ถ้าคุณต้องการทำการจับคู่อย่างมีประสิทธิภาพอัลกอริทึมAho Corasickเป็นตัวเลือกที่ดีทีเดียว

แน่นอนว่าคุณอาจต้องการประมวลผลการส่งล่วงหน้าเพื่อแทนที่การสะกดผิดปกติ ('$' -> 's', '@' -> 'a', '|' '<> ->' k 'ฯลฯ )


ขอบคุณสิ่งที่ฉันกำลังมองหาขอบคุณ! นี่คือการใช้งานจาวา: hkn.eecs.berkeley.edu/~dyoo/java
Remi Mélisson

0

แทนที่จะโหลดลงในสตริงคงที่ [] ใช้ HashMap [] หรือต้นไม้ไบนารีชนิดอื่น ๆ (ถ้าคุณต้องการปรับปรุงการค้นหา) ทำให้สตริงเป็นคีย์ของคุณในแฮช แยกสตริงของคุณด้วยช่องว่างและลบเครื่องหมายวรรคตอน จากนั้นคุณสามารถค้นหา HashMap สำหรับแต่ละคำในการแบ่งสตริงของคุณ ถ้า hashmap กลับมาพร้อมกับค่าที่ไม่เป็นโมฆะคุณก็รู้ว่าคุณมีคำไม่ดี

สิ่งที่ล้มเหลวที่นี่คือปัญหา Clbuttic ที่มีคนเพิ่มตัวอักษรแบบสุ่มรอบคำที่ไม่ดีเช่น bhassda


ฉันคิดว่าข้อแม้สุดท้ายคือสิ่งที่ทำให้โซลูชันนี้ไร้ประโยชน์อย่างมาก - ไม่มีทางที่จะขยายไปสู่สิ่งใดนอกจากการจับคู่ทั้งคำ

นั่นคือคำแถลงการณ์ที่ยุติธรรม แต่มันก็ยากที่จะจับทุกสิ่งที่เป็นไปได้ที่จิตใจมนุษย์สามารถคิดออกมาเพื่อหลบเลี่ยงตัวกรองที่ดูหมิ่น คุณสามารถสร้างนิพจน์ปกติขนาดใหญ่ด้วยคำสั่ง OR เพื่อรวมตัวเลือกทั้งหมดแล้วจับคู่ regex กับอินพุต หรือคุณสามารถเลือกจากฐานข้อมูลด้วย "เขตข้อมูลคำไม่ดี" จากฐานข้อมูลที่มี RLIKE กับอินพุต Return หมายถึงคำที่ไม่ดีและจะส่งคืนคำที่ไม่ดีด้วย

@Suroot มันไม่ยากที่จะรวบรวมคำหรือวลีใด ๆ ด้วยการจับคู่ออกเสียงตามที่คำถามของฉันพูดถึง การจับคู่แบบสัมบูรณ์จะไม่ทำงานหรือปรับขนาด แต่การจับคู่การออกเสียงจะทำงานใกล้เคียงกับ 100% ของเวลาเมื่อคุณปรับแต่งตามที่คุณจะได้รับ

-1

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

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

นอกจากนี้คุณจะสิ้นสุดการวนรอบสตริง N ทั้งหมดโดยที่ N คือจำนวนคำในบัญชีดำของคุณ คำแนะนำในการใช้ Set หรือ HashMap นั้นเป็นการปรับปรุงสิ่งต่าง ๆ อย่างแน่นอน

ในกรณีส่วนใหญ่อัลกอริทึมที่ใช้สถานะเชิงเส้นจะดีที่สุดและเร็วที่สุด ฉันเขียนวิธีแก้ปัญหาสำหรับClean Speakและใช้อัลกอริธึมชนิดนี้ร่วมกับระบบจับคู่ phonic ก่อนกระบวนการ นี่เป็นทางออกเดียวที่ไม่ซับซ้อนเมื่อฝังความหยาบคาย (หาก foo คือความหยาบคายการฝังเป็น foosucker) และสามารถรักษาประสิทธิภาพระดับสูงไว้ได้ นอกจากนี้ยังปรับขยายได้ดีสำหรับภาษาอื่น ๆ โดยไม่ต้องติดตั้ง codexes ใหม่

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

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


-2

สิ่งที่คุณต้องการทำในกรณีเช่นนี้คือพิจารณาว่าคำใดในสองรายการที่เล็กกว่า สมมติว่ารายการ "verboten" ของคุณมี 2,000 คำและการส่งผู้ใช้สูงสุดคือ 500 คำ ในกรณีนี้คุณจะวนซ้ำคำในการส่งผู้ใช้และค้นหาทีละคำในรายการคำที่ต้องห้ามและในทางกลับกัน

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

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