มีตัวกรอง anti-Bloom หรือไม่?


25

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

มี "ฟิลเตอร์ต่อต้านบลูม" ซึ่งมีพฤติกรรมตรงกันข้ามหรือไม่?

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

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


สำหรับผู้ที่ต้องการการรักษาที่เป็นทางการมากขึ้นให้เขียนถ้าตัวกรอง Bloom คิดว่าเป็นของใหม่,มิฉะนั้นและเขียนถ้าเป็นจริงและมิฉะนั้นx b ( x ) = 0 n ( x ) = 1 x n ( x ) = 0b(x)=1xb(x)=0n(x)=1xn(x)=0

จากนั้น ; ; ; สำหรับบาง<1P r [ b ( x ) = 0 | n ( x ) = 1 ] = α P r [ b ( x ) = 1 | n ( x ) = 0 ] = 0 P r [ bPr[b(x)=0|n(x)=0]=1Pr[b(x)=0|n(x)=1]=αPr[b(x)=1|n(x)=0]=00 < α < 1Pr[b(x)=1|n(x)=1]=1α0<α<1

ฉันถามว่า: มีโครงสร้างข้อมูลที่มีประสิทธิภาพหรือไม่โดยใช้ฟังก์ชั่นกับเช่น ; ; ; ? 0 < β < 1 P r [ b ( x ) = 0 | n ( x ) = 0 ] = β P r [ b ( x ) = 0 | n ( x ) = 1 ] = 0 P r [ b ( x ) = 1 | n ( xb0<β<1Pr[b(x)=0|n(x)=0]=βPr[b(x)=0|n(x)=1]=0P r [ b ( x ) = 1 | n ( x ) = 1 ] = 1Pr[b(x)=1|n(x)=0]=1βPr[b(x)=1|n(x)=1]=1


แก้ไข:ดูเหมือนว่าคำถามนี้ถูกถามมาก่อนใน StackExchange เช่น/programming/635728และ/cstheory/6596พร้อมคำตอบที่หลากหลายจาก "ไม่สามารถเป็นได้ ทำ "ถึง" สามารถทำได้ในราคา "เป็น" มันเป็นเรื่องเล็กน้อยที่จะทำโดยการกลับค่าของ " ยังไม่ชัดเจนสำหรับฉันคำตอบที่ถูกต้องคืออะไร สิ่งที่เป็นที่ชัดเจนว่าโครงการอาร์แคชของบางประเภท (เช่นหนึ่งที่แนะนำโดย Ilmari Karonen) ทำงานค่อนข้างดีเป็นเรื่องง่ายที่จะใช้และผลในการลด 50% ในเวลาที่จะเรียกใช้รหัสของฉันb


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

คุณอาจจะสนใจในการพูดคุยต่อไปนี้: ตัวกรองความเป็นสมาชิกชุดความพึงพอใจตาม
Kaveh

@Kaveh: ขอบคุณสำหรับตัวชี้จะดู
András Salamon

คำตอบ:


12

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

เลือกพารามิเตอร์และ ; ค่าในทางปฏิบัติอาจจะพูดว่าและ16 ให้เป็นฟังก์ชั่นแฮ็คเข้ารหัสที่ปลอดภัยผลิต (อย่างน้อย) บิตk n = 128 k = 16 H n + knkn=128k=16Hn+k

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

  • การเพิ่มค่าใหม่การกรองคำนวณที่หมายถึงคนแรกบิตและหมายถึงต่อไปนี้บิต(x) ให้Jixi k j n H ( x ) a i = jij=H(x)ikjnH(x)ai=j

  • เพื่อทดสอบว่าค่ามีการเพิ่มตัวกรองคำนวณ , ข้างต้นและตรวจสอบว่าJ' ถ้าใช่กลับจริง มิฉะนั้นคืนเท็จฉันxa i = j ij=H(x)ai=j

การเรียกร้องที่ 1:ความน่าจะเป็นของเท็จบวก (= ค่าใหม่อ้างตู่ได้รับการเห็น) เป็นK} สิ่งนี้สามารถทำให้มีขนาดเล็กตามอำเภอใจในราคาที่พอเหมาะในพื้นที่เก็บข้อมูลโดยเพิ่ม ; โดยเฉพาะอย่างยิ่งสำหรับความน่าจะเป็นนี้มีความสำคัญน้อยมากในทางปฏิบัติมีขนาดเล็กกว่าความน่าจะเป็นของการบวกผิดเนื่องจากฮาร์ดแวร์ทำงานผิดปกติ n n 1281/2n+knn128

โดยเฉพาะอย่างยิ่งหลังจากที่ค่าที่แตกต่างกันได้รับการตรวจสอบและเพิ่มตัวกรองน่าจะเป็นของเท็จบวกอย่างน้อยคนหนึ่งที่เกิดขึ้นคือ1} ตัวอย่างเช่นกับและจำนวนของค่าที่แตกต่างกันจำเป็นต้องได้รับในเชิงบวกเท็จกับความน่าจะเป็น 50% เป็นเรื่องเกี่ยวกับ{72}( N 2 - N ) / 2 n + k + 1 n = 128 k = 16 2 ( n + k ) / 2 = 2 72N(N2N)/2n+k+1n=128k=162(n+k)/2=272

การอ้างสิทธิ์ 2:ความน่าจะเป็นของการลบแบบผิด ๆ (= มูลค่าเพิ่มก่อนหน้านี้ที่อ้างว่าเป็นเท็จ) ไม่เกินโดยที่คือจำนวนค่าที่แตกต่างกันที่เพิ่มลงในตัวกรอง (หรือโดยเฉพาะอย่างยิ่งจำนวนของค่าที่แตกต่างที่เพิ่มหลังจากค่าเฉพาะที่ถูกทดสอบนั้นถูกเพิ่มเข้าไปในตัวกรองล่าสุด) N1(12k)N1exp(N/2k)<N/2kN


ps การใส่ "ความประมาทเลินเล่อ" ลงในมุมมองการเข้ารหัส 128 บิตโดยทั่วไปถือว่าไม่สามารถแตกได้ด้วยเทคโนโลยีที่รู้จักในปัจจุบัน ได้รับการเท็จบวกจากโครงการนี้กับเป็นที่น่าจะเป็นคนที่ถูกต้องคาดเดาคีย์การเข้ารหัส 128 บิตลับของคุณในครั้งแรกของพวกเขา (ด้วยและมันมีโอกาสน้อยกว่าประมาณ 65,000 เท่า)n = 128 k = 16n+k=128n=128k=16

แต่ถ้าที่ยังคงใบคุณรู้สึกประสาทไม่มีเหตุสมควรคุณสามารถสลับไป ; มันจะเป็นสองเท่าของความต้องการจัดเก็บข้อมูลของคุณ แต่ฉันสามารถเดิมพันที่คุณรวมใด ๆ ที่คุณต้องการการดูแลการตั้งชื่อที่ไม่มีใครจะเคยเห็นในเชิงบวกเท็จกับ - สมมติว่าฟังก์ชั่นแฮชไม่เสียอยู่แล้วn = 256n=256n=256


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

+1 ดีมาก - ความเข้าใจของฉันคือการแก้ปัญหาประสิทธิภาพพื้นที่ด้วยการให้โอกาส (เล็กมาก) ในการตอบ "ไม่ใหม่" อย่างไม่ถูกต้องเมื่อจริง ๆ แล้วเป็นรายการใหม่ การวิเคราะห์ในทางปฏิบัติและดีมาก
Patrick87

1
การอ้างสิทธิ์ 1 เป็นการระบุว่าฟังก์ชันแฮชที่เหมาะสมมีความน่าจะเป็นที่จะเกิดการชนน้อย นี่เป็นจริงในทางปฏิบัติแล้วถ้าเป็นอย่างน้อย 50 หรือมากกว่านั้น สำหรับแอปพลิเคชันของฉันและงานได้ดีด้วยฟังก์ชั่นแฮ็ค 64 บิตที่ไม่มีการเข้ารหัสที่ปลอดภัย n = 44 k = 20n+kn=44k=20
András Salamon

@ AndrásSalamon: ทรูแม้ว่าฟังก์ชันแฮชเข้ารหัสลับที่เชื่อถือได้ของจริงให้การรับประกันเล็กน้อยที่แข็งแกร่ง: คือว่ามันเป็นไปไม่ได้ที่จะหาชนปัจจัยการผลิตแม้ว่าคุณจะพยายามที่จะจงใจมองหาพวกเขา ด้วยขนาดใหญ่พอที่ (เช่นตามที่ฉันแนะนำไว้ข้างต้น) ซึ่งหมายความว่าการจัดเก็บข้อมูลเต็มไม่จำเป็นแม้ว่าค่าใช้จ่ายของการบวกเป็นเท็จสูงและแม้ว่าอาจมีฝ่ายตรงข้ามที่พยายามหา แน่นอนถ้าคุณไม่ต้องการการรับประกันที่แข็งแกร่งนักความเสี่ยงในการชนที่ค่อนข้างสูงนั้นสามารถยอมรับได้ n = 128nn=128
Ilmari Karonen

1
@ Newtopian เหตุผลที่ฉันระบุฟังก์ชั่นการเข้ารหัสลับคือสำหรับสิ่งเหล่านั้นไม่มีวิธีที่รู้จักในการสร้างการชนได้อย่างมีประสิทธิภาพมากกว่าการใช้กำลังดุร้าย (เช่นโดยการทดสอบอินพุตจำนวนมากและเลือกสิ่งที่ชนกัน) หัก (เหมือนพูด MD5 ปัจจุบัน) ดังนั้นสำหรับแฮ็คการเข้ารหัสเราสามารถสรุปได้อย่างปลอดภัยว่าอัตราการชนนั้นเหมือนกับฟังก์ชันแฮชสุ่มในอุดมคติ การใช้ฟังก์ชั่นแฮชสากลหรือ MAC แบบคีย์ (พร้อมรหัสลับแบบสุ่ม) จะทำให้การรับประกันนี้แข็งแกร่งยิ่งขึ้น
Ilmari Karonen

8

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

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


ดูคำตอบที่ยอมรับได้เนื่องจากคำถามมีเหมือนกัน
Joe

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

1
คำตอบนี้สมเหตุสมผลอย่างสมบูรณ์และดูเหมือนจะตอบคำถามของฉัน แต่อาจไม่ใช่วิญญาณ
András Salamon

@DW ขอบคุณที่สละเวลาในการอัปเดตคำตอบ ฉันอยากจะปล่อยให้นี่เป็นคำตอบในตอนนี้แม้ว่าฉันจะยังคงคัดค้านภาษาที่ใช้ในการอธิบายความไร้ประสิทธิภาพของตัวกรองต่อต้านการเบ่งบานนอกเหนือไปจากการคิด .. ปล่อย -1 ไปก่อน ล้างความคิดเห็นที่ล้าสมัยแล้ว
Patrick87

@DW โดย "false negative" ฉันตั้งใจจะตอบสนอง "ใหม่" เมื่อคำตอบควรเป็น "ไม่ใช่เรื่องใหม่" (ค่อนข้างตรงกันข้าม "ไม่ใช่เรื่องใหม่" เป็นกรณีบวกที่นี่) คุณไม่จำเป็นต้องบันทึก "ข้อมูลทั้งหมดที่เคย" เพื่อดึงออกแม้ว่าฉันจะเชื่อว่าคุณจำเป็นต้องบันทึกองค์ประกอบทั้งหมด (เพียงแค่ ไม่ใช่ทุกองค์ประกอบยกเว้นคุณเต็มใจที่จะยอมรับโอกาสผิดพลาดที่มีความหมายตามสมมุติฐานสำหรับคำตอบอื่น ๆ ของคำถามที่นี่)
Patrick87

6

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

คุณจะได้รับ "ใหม่" อย่างถูกต้องเสมอหากคุณไม่เคยเห็นรายการของแฮชมาก่อน คุณจะได้รับ "ไม่ใช่ใหม่" อย่างถูกต้องเสมอหากคุณเห็นเฉพาะรายการที่แฮชเมื่อคุณเห็นรายการเดียวกัน ครั้งเดียวที่คุณจะได้รับ "ใหม่" เมื่อคำตอบที่ถูกต้องคือ "ไม่ใช่ใหม่" คือถ้าคุณเห็นรายการ A จากนั้นดูรายการ B จากนั้นดูรายการ A อีกครั้งและทั้ง A และ B แฮชกับสิ่งเดียวกัน ที่สำคัญคุณไม่สามารถรับ "ไม่ใช่ใหม่" ได้อย่างไม่ถูกต้อง


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

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

@WanderingLogic การใช้ตัวนับ saturating ขนาดเล็กแทนบิตเดียวช่วยให้การลบได้รับการสนับสนุน (ที่ค่าใช้จ่ายของความจุและเฉพาะในกรณีที่ตัวนับไม่สูงสุดอย่างเห็นได้ชัด)
Paul A. Clayton

4

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

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

สิ่งนี้ไม่ได้ตอบคำถามของคุณ แต่ในกรณีที่ จำกัด นี้ตัวกรอง Bloom B ทำงานได้ดีกับพฤติกรรม "ตัวกรองการป้องกันการเบ่งบาน" ที่คุณกำลังมองหา

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


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

1
@ โจ: ฉันยอมรับว่าปัญหาไม่สามารถแก้ไขได้โดยทั่วไปดังนั้น จำกัด คำตอบของฉันในกรณีที่ส่วนประกอบนั้น จำกัด และเล็ก
หลงทางตรรกะ

1

vi

ตัวอย่างอาจเป็นที่อยู่ IP และคุณต้องการทราบทุกครั้งที่ปรากฏว่าคุณไม่เคยเห็นมาก่อน แต่มันยังคงเป็นขอบเขตที่ จำกัด ดังนั้นคุณจึงรู้ว่าคุณคาดหวังอะไร

ทางออกที่แท้จริงนั้นง่ายมาก:

  1. เพิ่มรายการทั้งหมดของคุณไปยังตัวกรองการนับจำนวนดอก
  2. 1
  3. หลังจากเห็นรายการใหม่จริงให้ลบออกจากตัวกรอง

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

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