PostgreSQL полнотекстовый поиск случайным образом отбрасывая лексемы
(Все это было сделано с PostgreSQL 9.0.1 в Ubuntu 10.04, FWIW.)
Я попытался написать свою собственную функцию lexize для PostgreSQL специально для имен, основанную на алгоритме двойного метафона. Чтобы создать функцию C lexize, я начал с примера dict_xsyn и в основном поменял двойной метафон на поиск синонимов.
Но, возможно, 20% времени to_tsvector
вызывается, кажется, отбрасывает лексемы. В качестве примера я создал таблицу со списком имен Бюро переписей США.
db=# select * from names order by rank limit 8;
name | freq | cumfreq | rank
----------+-------+---------+------
SMITH | 1.006 | 1.006 | 1
JOHNSON | 0.81 | 1.816 | 2
WILLIAMS | 0.699 | 2.515 | 3
JONES | 0.621 | 3.136 | 4
BROWN | 0.621 | 3.757 | 5
DAVIS | 0.48 | 4.237 | 6
MILLER | 0.424 | 4.66 | 7
WILSON | 0.339 | 5 | 8
(8 rows)
Затем мы можем добавить векторный столбец и заполнить его to_tsvector
моего словаря метафонов:
db=# alter table names add column vec tsvector;
ALTER TABLE
db=# update names set vec=to_tsvector('public.names', name);
UPDATE 88799
db=# select * from names order by rank limit 8;
name | freq | cumfreq | rank | vec
----------+-------+---------+------+-------------------------------
SMITH | 1.006 | 1.006 | 1 |
JOHNSON | 0.81 | 1.816 | 2 | 'ANSN':1 'JNSN':1 'johnson':1
WILLIAMS | 0.699 | 2.515 | 3 |
JONES | 0.621 | 3.136 | 4 |
BROWN | 0.621 | 3.757 | 5 |
DAVIS | 0.48 | 4.237 | 6 |
MILLER | 0.424 | 4.66 | 7 | 'MLR':1 'miller':1
WILSON | 0.339 | 5 | 8 | 'ALSN':1 'FLSN':1 'wilson':1
(8 rows)
Куча полей vec просто пуста! По факту:
db=# select count(1) from names where vec = to_tsvector('');
count
-------
41101
(1 row)
Я могу выполнить это массовое обновление, а затем многократно подсчитывать несовпадающие поля и каждый раз получать разные значения, потому что разные строки не могут вычислить реальные векторы.
Но я думаю, что с моей функцией lexize все в порядке?
db=# alter table names drop column vec; alter table names add column lexemes varchar[];
ALTER TABLE
ALTER TABLE
db=# update names set lexemes=ts_lexize('dmetaphonedict', name);
UPDATE 88799
db=# select * from names order by rank limit 10;
name | freq | cumfreq | rank | lexemes
----------+-------+---------+------+----------------------
SMITH | 1.006 | 1.006 | 1 | {smith,SM0,XMT}
JOHNSON | 0.81 | 1.816 | 2 | {johnson,JNSN,ANSN}
WILLIAMS | 0.699 | 2.515 | 3 | {williams,ALMS,FLMS}
JONES | 0.621 | 3.136 | 4 | {jones,JNS,ANS}
BROWN | 0.621 | 3.757 | 5 | {brown,PRN}
DAVIS | 0.48 | 4.237 | 6 | {davis,TFS}
MILLER | 0.424 | 4.66 | 7 | {miller,MLR}
WILSON | 0.339 | 5 | 8 | {wilson,ALSN,FLSN}
MOORE | 0.312 | 5.312 | 9 | {moore,MR}
TAYLOR | 0.311 | 5.623 | 10 | {taylor,TLR}
(10 rows)
db=# select count(1) from names where array_length(lexemes,1)=0;
count
-------
0
(1 row)
Я могу делать это снова и снова и каждый раз получать 0 несоответствий.
Я создаю соответствующие словари и конфигурации текстового поиска с:
CREATE OR REPLACE FUNCTION ddmetaphonedict_init(internal)
RETURNS internal
AS '$libdir/dict_dmetaphone'
LANGUAGE C STRICT;
CREATE OR REPLACE FUNCTION ddmetaphonedict_lexize(internal, internal, internal, internal)
RETURNS internal
AS '$libdir/dict_dmetaphone'
LANGUAGE C STRICT;
CREATE TEXT SEARCH TEMPLATE dmetaphonedict_template (
LEXIZE = ddmetaphonedict_lexize,
INIT = ddmetaphonedict_init
);
CREATE TEXT SEARCH DICTIONARY dmetaphonedict (
TEMPLATE = dmetaphonedict_template
);
COMMENT ON TEXT SEARCH DICTIONARY dmetaphonedict IS 'dictionary for names, using dmetaphone';
create text search configuration names (copy=english);
alter text search configuration names alter mapping for asciiword, asciihword, word, hword with dmetaphonedict;
Практически прямо из примера dict_xsyn.
В чем дело? Что я могу сделать, чтобы выяснить, где эти вещи сбрасываются?
ДОБАВЛЕНО: Просто попробовал это с 9.1. Скорость, с которой to_tsvector создает плохой цветатор, значительно уменьшена (5 (всего 5, а не 5k) до 7000 записей из 80000+). Но они все еще там.
1 ответ
Я хотел бы сначала устранить to_tsvector() в качестве причины.
Я мог бы сначала попытаться изменить to_tsvector(), чтобы он возвращал константу. Например, измените его так, чтобы оно возвращало "ANSN:1" JNSN ":1" johnson ":1" независимо от его входных аргументов. (Даже если входные аргументы равны NULL.) Если ваше массовое обновление все еще оставляет дыры в столбце "vec", я думаю, что это очистит to_tsvector().
Я прав в этом?
Также рассмотрим двухэтапный процесс, использующий lexize() для заполнения столбца "лексемы", а затем другую функцию для чтения лексем и получения значений в столбце "vec".