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


11

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

เอกสาร postgres พูดคุยเกี่ยวกับการสร้างts_vectorดัชนีในคอลัมน์ที่ต่อกันเช่น:

CREATE INDEX pgweb_idx ON pgweb 
    USING gin(to_tsvector('english', title || ' ' || body));

ซึ่งฉันสามารถค้นหาดังนี้:

... WHERE 
      (to_tsvector('english', title||' '||body) @@ to_tsquery('english', 'foo'))

อย่างไรก็ตามหากฉันต้องการค้นหาเฉพาะชื่อบางครั้งแค่เนื้อหาและบางครั้งทั้งสองฉันจะต้องมีดัชนีแยก 3 ตัว และถ้าฉันเพิ่มในคอลัมน์ที่สามนั่นอาจเป็น 6 ดัชนีและอื่น ๆ

อีกทางเลือกหนึ่งที่ฉันไม่ได้เห็นในเอกสารเป็นเพียงการจัดทำดัชนีสองคอลัมน์แยกกันจากนั้นใช้WHERE...ORแบบสอบถามปกติ:

... WHERE
      (to_tsvector('english', title) @@ to_tsquery('english','foo'))
    OR
      (to_tsvector('english', body) @@ to_tsquery('english','foo'))

การเปรียบเทียบทั้งสองแถวบน ~ 1 ล้านแถวดูเหมือนจะไม่มีประสิทธิภาพที่แตกต่างกัน

ดังนั้นคำถามของฉันคือ:

เหตุใดฉันจึงต้องการเชื่อมดัชนีเข้าด้วยกันเช่นนี้แทนที่จะสร้างดัชนีคอลัมน์แยกกัน? ข้อดี / ข้อเสียของทั้งคู่คืออะไร

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


ฉันไม่แน่ใจจริง ๆ ว่าการเชื่อมต่อtitleเข้าไปในbodyแล้วจัดทำดัชนีที่จะให้คุณค่ามากแม้ว่าฉันจะเปิดการแก้ไข ฉันอาจจะติดดัชนีแยกกัน นอกจากนี้หากมีข้อผิดพลาดอย่างใดอย่างหนึ่งที่ต้องการให้คุณต่อกันฉันคิดว่าคุณสามารถเรียกใช้คิวรีแบบเฉพาะกิจได้
swasheck

คุณเดาถูกแล้ว ฉันอยากจะแนะนำให้คุณตอบด้วยตนเองถ้าไม่มีใครอื่นสไตล์ Jeopardy ที่นี่
jcolebrand

คำตอบ:


4

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

--search any "field" for quick:
select 'quick:1A brown:2B quick:3C'::tsvector @@ 'quick'::tsquery; --true

--search B "field" for quick:
select 'quick:1A brown:2B quick:3C'::tsvector @@ 'quick:B'::tsquery; --false

--search B or C "fields" for quick:
select 'quick:1A brown:2B quick:3C'::tsvector @@ 'quick:BC'::tsquery; --true

คุณอาจต้องการเชื่อมต่อ tsvectors เพื่อให้คุณสามารถใช้น้ำหนักกับพวกเขาแยกต่างหากจากนั้นรวมเข้าด้วยกัน:

select
  setweight( name_column::tsvector, 'A') || setweight( phone_column::tsvector, 'B');

3

อันที่จริงทางเลือกที่จะใช้ที่มีหรือไม่และ

หากคุณมีดัชนีของ tsvector (เนื้อหา + ชื่อเรื่อง) และคุณกำลังค้นหาอยู่คำที่ค้นหาอาจอยู่ในชื่อหรือในเนื้อหา

นอกจากนี้ - เมื่อทำการทดสอบตรวจสอบให้แน่ใจว่าคุณมีจำนวนแถวที่เหมาะสมในตาราง

กรณีที่ง่ายที่สุดซึ่งควรแสดงความแตกต่างที่ดี: ค้นหาสองคำ - หนึ่งในนั้นที่น่าจะเป็นในชื่อ และอื่น ๆ - ที่มีแนวโน้มมากที่จะอยู่ในร่างกาย แต่ตรวจสอบให้แน่ใจว่ามีแถวไม่มากที่ตรงกับเกณฑ์ทั้งสอง ตัวอย่างเช่น - คุณอาจมี 30% ของคำว่า "depesz" อยู่ในร่างกาย คุณมีโอกาส ~ 30% ในการมี "mysql" ในชื่อ แต่การมี "depesz และ mysql" ในฟิลด์ใด ๆ ในแถวเดียวกันนั้นไม่น่าเป็นไปได้ จากนั้นตรวจสอบประสิทธิภาพด้วยดัชนีดังกล่าว


ฮาจุดดีบนหรือ vs และฉันจะอัปเดตคำถาม ฉันทำกับ 1 ล้านแถว - ไม่ต้องรออีกต่อไปที่จะแทรก :)
latentflip

1
ขอบคุณสำหรับการวางโดย depesz - เราได้รับคำถาม postgres ไม่กี่วันนี้ดังนั้นฉันหวังว่าคุณจะติดอยู่รอบ ๆ :-)
แจ็คพูดลอง topanswers.xyz

@ แจ็ค: ไม่แน่ใจว่าฉันจะ - ฉันพบเว็บไซต์ stackexchange น้อยกว่าและใช้งานได้น้อยลง ฉันมักจะพยายามรับ RSS แต่ในเว็บไซต์ stackexchange rss นั้นไร้ประโยชน์มาก - มลพิษมากจากคำถามรุ่นเก่า

ฉันได้สร้างฟีด RSS ให้คุณที่นี่ - คุณยินดีที่จะลองดูไหม? ฉันยินดีที่จะใช้ความพยายามในการกรองสิ่งที่คุณไม่น่าสนใจที่จะได้รับโอกาสให้คุณมีส่วนร่วมมากขึ้นในเว็บไซต์ :-)
แจ็คพูดว่าลอง topanswers.xyz

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