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

Другие вопросы по тегам