Meus caros,
Devido a um pequeno desafio (Valdisnei vs Walt Disney), mantendo o uso
de Levenschtein com índice de erro 1 apenas para palavras iniciadas em
W, U e V, precisei reescrever a função para ignorar os espaços em
branco, pois o T passava a ter peso por vir ao final de uma palavra,
gerando um resultado distinto.
Eis o que sobrou:
TESTES:
SELECT LEVENSHTEIN(LATINEX('Joaum Culioins da Çilva Roxa'),
LATINEX('João Culhões da Silva Rocha'));
SELECT LEVENSHTEIN(LATINEX('Valdisnei'), LATINEX('Walt Disney'));
SELECT LEVENSHTEIN(LATINEX('Uólaci Martinez de Çouza Broxado'),
LATINEX('Wallace Martins de Sousa Brochado'));
SELECT LEVENSHTEIN(LATINEX('Wanezza Manguabeira da Costta'),
LATINEX('Vanessa Mangabeira da Costa'));
SELECT LEVENSHTEIN(LATINEX('Amiltão De Georgio'), LATINEX('Hamilton Di
Giorgio'));
SELECT LATINEX('Joaum Culioins da Çilva Roxa'), LATINEX('João Culhões
da Silva Rocha');
SELECT LATINEX('Valdisnei'), LATINEX('Walt Disney');
SELECT LATINEX('Uólaci Martinez de Çouza Broxado'), LATINEX('Wallace
Martins de Sousa Brochado');
SELECT LATINEX('Wanezza Manguabeira da Costta'), LATINEX('Vanessa
Mangabeira da Costa');
SELECT LATINEX('Amiltão De Georgio'), LATINEX('Hamilton Di Giorgio');
-- Criação da função de peso do som das consoantes para cálculo de soundex latin
-- Function: latinex(character varying)
-- DROP FUNCTION latinex(character varying);
CREATE OR REPLACE FUNCTION latinex(character varying)
RETURNS character AS
$BODY$
DECLARE
texto VARCHAR;
resultado VARCHAR;
i INT;
ipesom INT;
valorPrimeiraLetra INT;
c VARCHAR;
BEGIN
texto = $1;
texto = UPPER(texto);
texto = TRANSLATE(texto, 'ãO', 'M');
texto = TRANSLATE(texto, 'ÃO', 'M');
texto = TRANSLATE(texto, 'õE', 'M');
texto = TRANSLATE(texto, 'ÕE', 'M');
texto = TRANSLATE(texto, 'ç', 'C');
texto = TRANSLATE(texto, 'Ç', 'C');
texto = TRANSLATE(texto, 'ñ', 'N');
texto = TRANSLATE(texto, 'Ñ', 'N');
resultado = SUBSTRING(texto,1,1);
valorPrimeiraLetra = pesom(resultado);
i=2;
WHILE i < LENGTH(texto) LOOP
c = SUBSTRING(texto, i, 1);
ipesom = pesom(c);
IF (
NOT (ipesom = 0) AND
NOT (valorPrimeiraLetra = ipesom)
) THEN
resultado = resultado || ipesom;
END IF;
IF (
NOT (c = ' ') AND
NOT (c = '''') AND
NOT (c = '-') AND
NOT (c = 'A') AND
NOT (c = 'E') AND
NOT (c = 'I') AND
NOT (c = 'O') AND
NOT (c = 'U')
) THEN
valorPrimeiraLetra = ipesom;
ipesom = 0;
END IF;
i := i + 1;
END LOOP;
WHILE LENGTH(resultado) < 4 LOOP
resultado = resultado || '0';
END LOOP;
RETURN resultado;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION latinex(character varying)
OWNER TO postgres;
Em 10 de julho de 2013 15:01, Pablo Sánchez <[email protected]> escreveu:
> Achei a página original do código. Dá para ver que eu não fiz muita
> coisa além de colocar uns translates bestas.
>
> http://www.mloyola.com.br/site/busca-fonetica-postgresql
>
> Menção honrosa para o Marcus Loyola que foi quem disponibilizou o
> código original.
>
> Em 10 de julho de 2013 14:50, Pablo Sánchez <[email protected]> escreveu:
>> Alguém tem idéia de como eu faço para mandar essa contribuição para o
>> pessoal do Postgres para que tenhamos lá um suporte para soundex para
>> latin? E alguém tem idéias para acrescentar, já que eu só fiz um pouco
>> de nada que já me resolve horrores aqui, mas que com certeza não é nem
>> 10% do total para fechar com chave de ouro esse código?
>>
>> Em 10 de julho de 2013 14:45, Pablo Sánchez <[email protected]> escreveu:
>>> Já resolvi aqui a questão.
>>>
>>> Segue o que eu implementei com base em um código que encontrei na Net
>>> (mas fechei a aba e estava em modo anônimo, perdi qual era - créditos
>>> para outra pessoa).
>>>
>>> Coloquei o peso do Ç igual ao peso de C que é igual ao peso de S e de
>>> X e coloquei o ÃO e ÕE com o peso de M caso o cara tenha escrito um
>>> JOAUM ao invés de JOÃO.
>>>
>>> Só respondendo: não quero ser muito flexível, por isso eliminei uma
>>> penca de coisas e deixei o índice apenas como <= 1. E sim, o cadastro
>>> de detentos é sempre feito com o nome completo. Só para te dar uma
>>> base de como ficou bacana, o teste foi assim:
>>>
>>> SELECT LATINEX('Joaum Culioins da Çilva Roxa'), LATINEX('João Culhões
>>> da Silva Rocha');
>>>
>>> Veja que a assinatura de ambos é idêntica.
>>>
>>> Meu problema está apenas com o raio da letra W que pode ter som de V
>>> ou se U como em Wallace e Watson. Nesse caso a assinatura de todo o
>>> restante é idêntica, exceto a primeira letra. Não posso descartar, mas
>>> posso colocar uma margem de 1 se eu simplesmente pegar os resultados
>>> como parte de levenschtein e manter o índice em <= 1. Acredito que
>>> isso me ajude também a pegar similaridades como Jasmin e Yasmin.
>>>
>>> Assim, eis o que eu tenho:
>>>
>>> -- Resultado levenshtein = 0, porque o primeiro caractere é idêntico
>>> SELECT LEVENSHTEIN(LATINEX('Joaum Culioins da Çilva Roxa'),
>>> LATINEX('João Culhões da Silva Rocha'))
>>>
>>> -- Resultados levenshtein = 1, porque o primeiro caractere é o único que
>>> SELECT LEVENSHTEIN(LATINEX('Uólaci Culioins da Çilva Roxa'),
>>> LATINEX('Wallace Culhões da Silva Rocha'))
>>> SELECT LEVENSHTEIN(LATINEX('Wanezza Culioins da Çilva Roxa'),
>>> LATINEX('Vanessa Culhões da Silva Rocha'))
>>> SELECT LEVENSHTEIN(LATINEX('Amiltão Culioins da Çilva Roxa'),
>>> LATINEX('Hamilton Culhões da Silva Rocha'))
>>>
>>> --Criação da função de peso do som das consoantes para cálculo de soundex
>>> latin
>>>
>>> CREATE OR REPLACE FUNCTION pesom(CHARACTER)
>>> RETURNS INTEGER AS
>>> $BODY$
>>>
>>> SELECT
>>> CASE $1
>>> WHEN 'B' THEN 1
>>> WHEN 'C' THEN 2
>>> WHEN 'D' THEN 3
>>> WHEN 'F' THEN 1
>>> WHEN 'G' THEN 2
>>> WHEN 'J' THEN 2
>>> WHEN 'K' THEN 2
>>> WHEN 'L' THEN 4
>>> WHEN 'M' THEN 5
>>> WHEN 'N' THEN 5
>>> WHEN 'P' THEN 1
>>> WHEN 'Q' THEN 2
>>> WHEN 'R' THEN 6
>>> WHEN 'S' THEN 2
>>> WHEN 'T' THEN 3
>>> WHEN 'V' THEN 1
>>> WHEN 'X' THEN 2
>>> WHEN 'Z' THEN 2
>>> ELSE 0
>>> END
>>>
>>> $BODY$
>>> LANGUAGE 'sql' VOLATILE
>>> COST 100;
>>>
>>> ALTER FUNCTION pesom(CHARACTER) OWNER TO postgres;
>>>
>>>
>>> --Criação da função de peso do som das consoantes para cálculo de soundex
>>> latin
>>>
>>>
>>> CREATE OR REPLACE FUNCTION latinex(CHARACTER VARYING)
>>> RETURNS CHARACTER AS
>>> $BODY$
>>>
>>> DECLARE
>>> texto VARCHAR;
>>> resultado VARCHAR;
>>> i INT;
>>> ipesom INT;
>>> valorPrimeiraLetra INT;
>>>
>>> BEGIN
>>>
>>> texto = $1;
>>> texto = UPPER(texto);
>>> texto = TRANSLATE(texto, 'ãO', 'M');
>>> texto = TRANSLATE(texto, 'ÃO', 'M');
>>> texto = TRANSLATE(texto, 'õE', 'M');
>>> texto = TRANSLATE(texto, 'ÕE', 'M');
>>> texto = TRANSLATE(texto, 'ñ', 'N');
>>> texto = TRANSLATE(texto, 'Ñ', 'N');
>>> texto = TRANSLATE(texto, 'ç', 'C');
>>> texto = TRANSLATE(texto, 'Ç', 'C');
>>>
>>> resultado = SUBSTRING(texto,1,1);
>>>
>>> valorPrimeiraLetra = pesom(resultado);
>>>
>>> i=2;
>>>
>>>
>>> WHILE i < LENGTH(texto) LOOP
>>>
>>> ipesom = pesom(SUBSTRING(texto, i, 1));
>>>
>>> IF (NOT (ipesom = 0) AND NOT (valorPrimeiraLetra = ipesom)) THEN
>>> resultado = resultado || ipesom;
>>> END IF;
>>>
>>> valorPrimeiraLetra = ipesom;
>>>
>>> ipesom = 0;
>>>
>>> i := i + 1;
>>>
>>> END LOOP;
>>>
>>> WHILE LENGTH(resultado) < 4 LOOP
>>> resultado = resultado || '0';
>>> END LOOP;
>>>
>>> RETURN resultado;
>>>
>>> END;
>>>
>>> $BODY$
>>> LANGUAGE 'plpgsql' VOLATILE
>>> COST 100;
>>>
>>> ALTER FUNCTION latinex(CHARACTER VARYING) OWNER TO postgres;
>>>
>>> Em 10 de julho de 2013 11:13, Euler Taveira <[email protected]> escreveu:
>>>> On 10-07-2013 10:23, Pablo Sánchez wrote:
>>>>> Até o momento, tudo quase ok (tirando o fato de que não é para idiomas
>>>>> latinos, mas já é algo). Só que fiquei com dúvida sobre qual seria um
>>>>> bom valor para o índice Levenshtein. Estou extremamente compelido pelo
>>>>> índice 3, mas gostaria de opiniões.
>>>>>
>>>> Não existe índice bom ou ruim; tudo depende de (i) seus dados e (ii) o
>>>> quão flexível você quer ser. Faça bastante testes em uma "baseline" e
>>>> decida qual é o ideal.
>>>>
>>>>> Eis um exemplo de teste que mostrou-se satisfatório
>>>>>
>>>>> select soundex('Josefa Silva'), soundex('Joseph Silva');
>>>>> select levenshtein('Josefa Silva', 'Joseph Silva');
>>>>> select metaphone('Josefa Silva', 10), metaphone('Joseph Silva', 10);
>>>>> select dmetaphone('Josefa Silva'), dmetaphone('Joseph Silva');
>>>>> select dmetaphone_alt('Josefa Silva'), dmetaphone_alt('Joseph Silva');
>>>>>
>>>> Eu não aconselharia utilizar qualquer dessas funções em nomes completos.
>>>> O soundex, por exemplo, considera somente algumas posições (no mínimo 4
>>>> caracteres). O levenshtein utilizado com strings longas podem ter mais
>>>> do que 3 ou 4 mudanças. Ao invés disso, quebre o nome completo em nome e
>>>> sobrenome e faça uma comparação individual ou utilize uma composição de
>>>> funções de similaridade.
>>>>
>>>> Se você quer usar funções por similaridade, eu aconselho dar uma olhada
>>>> no pg_similarity [1]. Ele contém uma série de funções que podem te
>>>> auxiliar na tarefa de casamento flexível de strings.
>>>>
>>>>
>>>> [1] https://github.com/eulerto/pg_similarity
>>>>
>>>>
>>>> --
>>>> Euler Taveira Timbira - http://www.timbira.com.br/
>>>> PostgreSQL: Consultoria, Desenvolvimento, Suporte 24x7 e Treinamento
>>>> _______________________________________________
>>>> pgbr-geral mailing list
>>>> [email protected]
>>>> https://listas.postgresql.org.br/cgi-bin/mailman/listinfo/pgbr-geral
>>>
>>>
>>>
>>> --
>>>
>>>
>>>
>>>
>>>
>>> Pablo Santiago Sánchez
>>> ZCE ZEND006757
>>> [email protected]
>>> (61) 9975-0883
>>> http://www.sansis.com.br
>>> "Pluralitas non est ponenda sine necessitate"
>>
>>
>>
>> --
>>
>>
>>
>>
>>
>> Pablo Santiago Sánchez
>> ZCE ZEND006757
>> [email protected]
>> (61) 9975-0883
>> http://www.sansis.com.br
>> "Pluralitas non est ponenda sine necessitate"
>
>
>
> --
>
>
>
>
>
> Pablo Santiago Sánchez
> ZCE ZEND006757
> [email protected]
> (61) 9975-0883
> http://www.sansis.com.br
> "Pluralitas non est ponenda sine necessitate"
--
Pablo Santiago Sánchez
ZCE ZEND006757
[email protected]
(61) 9975-0883
http://www.sansis.com.br
"Pluralitas non est ponenda sine necessitate"
_______________________________________________
pgbr-geral mailing list
[email protected]
https://listas.postgresql.org.br/cgi-bin/mailman/listinfo/pgbr-geral