Birden çok sütunlu tam metin araması kaydeder, neden çalışma zamanında değil, dizinde concat?


11

Son birkaç gün içinde postgres tam metin aramasıyla karşılaştım ve birden fazla sütun arasında arama yaparken dizin oluşturma konusunda biraz kafam karıştı.

Postgres dokümanlarıts_vector , birleştirilmiş sütunlarda dizin oluşturma hakkında konuşur , şöyle:

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

ki ben böyle arama yapabilirsiniz:

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

Ancak, bazen sadece başlığı, bazen sadece gövdeyi ve bazen her ikisini de aramak isteseydim, 3 ayrı dizine ihtiyacım olurdu. Üçüncü bir sütuna eklersem, bu potansiyel olarak 6 dizin olabilir ve bu böyle devam eder.

Dokümanlarda görmediğim bir alternatif, iki sütunu ayrı ayrı dizine eklemek ve ardından normal bir WHERE...ORsorgu kullanmaktır :

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

Bu ikisinin ~ 1 milyon satır üzerinde karşılaştırılmasında performansta temel bir fark yok gibi görünüyor.

Benim sorum şu:

Neden sütunları tek tek dizine eklemek yerine bu tür dizinleri birleştirmek istesin ki? Her ikisinin de avantajları ve dezavantajları nelerdir?

En iyi tahminim, önceden önceden bilseydim, sadece her iki sütunu da (her seferinde bir tane) aramak isteyecektim ki, daha az bellek kullanan birleştirerek sadece bir dizine ihtiyacım olacaktı.


Düzeltmeye açık olsa da , titleiçine nasıl birleştirmek bodyve daha sonra bu çok değer verecek endeksleme emin değilim. Muhtemelen onları ayrı ayrı indekslemeye devam ediyorum. Ayrıca, bir şekilde bitirmek için gereken bazı tuhaf bir kerelik olsaydı, o zaman sadece ad-hoc sorgusunu çalıştırabilirsiniz sanırım.
swasheck

Tahmininiz doğru. Başka hiç kimse yapmazsa, Jeopardy tarzı burada kendi kendine cevap vermenizi öneririm.
jcolebrand

Yanıtlar:


4

Hayır, ayrı dizinlere ihtiyacınız yok. Ağırlıklar özelliğini kullanın. Bunlar sadece sorgulayabileceğiniz bir etikettir. (AD) ile sorgulamak için en fazla dört etiketiniz olabilir.

--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

Tsvector'ları birleştirmek isteyebilirsiniz, böylece ağırlıkları ayrı ayrı uygulayabilir ve daha sonra bir araya getirebilirsiniz:

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

3

Aslında alternatif , VE ile değil, OR ile kullanmak olacaktır .

Tsvector'da (gövde + başlık) dizininiz varsa ve içinde arama yapıyorsanız, aranan kelimeler başlıkta VEYA gövde içinde olabilir.

Ayrıca - test ederken, tabloda makul sayıda satır bulunduğundan emin olun.

İyi bir fark göstermesi gereken en basit durum: iki kelime bulun - bunlardan biri başlığında olması muhtemeldir. ve diğeri - vücutta olma olasılığı çok yüksektir. Ancak, her iki ölçütle eşleşen çok fazla satır olmadığından emin olun . Örneğin - "depesz" kelimesinin% 30'unun bedeninizde olması olabilir. Ayrıca "mysql" başlığında ~% 30 şansınız var. Ancak aynı satırdaki alanların herhangi birinde "depesz ve mysql" bulunması çok düşük bir olasılıktır. Ve sonra bu tür dizinlerle performansı kontrol edin.


Ha, iyi nokta, VEYA VE AND soruyu güncelleyeceğim. Ben 1 milyon satır ile yaptım - daha fazla eklemek için bekleyen rahatsız olamazdı :)
latentflip

1
Ben etrafında :-) sopa umuyoruz yüzden biz bu gün epeyce postgres soru alıyorsanız - depesz tarafından atılan için teşekkürler
Jack diyor topanswers.xyz deneyin

@Jack: emin değilim - stackexchange siteleri daha az kullanılabilir buldum. Genellikle RSS almaya çalışıyorum, ancak stackexchange sitelerinde rss oldukça işe yaramaz - eski soruların baskısından çok fazla kirlilik.

Burada sizin için bir RSS beslemesi oluşturdum - bunu denemek ister misiniz? Sizi siteye daha fazla dahil etme şansı elde etmek için ilginizi
çekmeyecek şeyleri filtrelemeye çalıştığım için mutluyum

Jack :) Ben ısırırım - abone oldum.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.