Como configurar BTS - Basic Text Search DataBlade para melhorar buscas textuais
O módulo Basic Text Search é um "plug-in" gratuito que já vem com as versões mais recentes do Informix e permite buscas textuais em modo mais avançado, performatico e flexivel que o LIKE ou MATCHES .
Informações
- Este modulo é baseado no software Open Source CLucene
- http://sourceforge.net/projects/clucene/
- É Free, não possui custo adicional ao cliente
- Todo este documento foi baseado na versão BTS 1.10 porém atualizado PARCIALMENTE com informações da versão BTS 2.00 que é fornecido com a versão 11.50 UC3.
- A versão do BTS distribuida com o Informix 11.50 UC4 possui novos recursos que não documentados aqui devido minha falta de oportunidade para avalia-los
NO FINAL DESTE DOCUMENTO A UM PEQUENO TEXTO COM RECOMENDAÇÕES BASICAS DE UTILIZAÇÃO
Pré-Requisitos
- Requer versão 11.10
- Configurar um UNICO VP (Virtual Process) no ONCONFIG especifico para o BTS.
- Necessário registar o modulo no banco de dados que irá utiliza-lo.
- Para os campos a serem pesquisados é necessário criar indice.
- Até a versão BTS 1.10 é necessário criar e administrar DbSpace externo (extspace) para os indices (onspaces -c -x).
Obs.: Este dbspace utiliza recursos de File System (diretório+arquivos) para salvar e acessar os dados. - Apartir da versão BTS 2.00 é possível gravar dados em sbspaces (Smart Blob Spaces ), permitindo assim a utilização do BTS em ambiente MACH11.
- Na versão 2.00 fornecida com IDS 11.50 UC3 existe um "bug" que ao registrar um bts em um banco, é necessário ter configurado um sbspace default .
Recursos
- Suporte carateres regionais configurado com GLS (Global Language Suporte) , incluindo UTF-8.(há execeções, ver na parte de limitações)
- Pode-se utilizar com os tipos de dados BLOB, CHAR, CLOB, LVARCHAR, NCHAR, NVARCHAR, VARCHAR desde que o dado seja gravado em formato de texto puro.
- Apartir da versão 1.10 (incluida no IDS 11.50) suporta pesquisa em dados XML
- STOPWORDS: são palvras que serão excluidas do indice criado e não serão consideradas em pesquisas. Este parametro tem por objetivo criar indices mais enchutos e evitar resultados indevidos nas pesquisas.
- Campos que contem XML, pode-se pesquisar limitando-se as TAGs existentes.
- Pode-se utilizar nas pesquisas condições boleanas: AND,&&,OR,||,NOT,!,-
- Pode-se utilizar os seguintes recursos de pesquisa:
- * (asterisco) para completar como multiplo caractere: cas* = casa,casarao
- ? (interrogação) para substituir um unico caractere : te?t = test, text
- ~ (til) para palavras aproximadas: nao~ = não,tao,sao
- ^ (circunflexo) eleva o escore da palavra na pesquisa: "casa lugar^2" = dobra o escore da palavras "lugar"
- ""~n (aspas+til+valor) pesquisa duas ou mais palavras que esteja N palavras proximas uma da outra. A ordem das palavras faz diferença: "casa cesar"~10 = "esta casa pode pertecer ao Cesar"
- [ TO ] (conchetes) define um "range" entre duas palavras seguindo a ordem alfabetica das palavras, é mais util para pesquisa com numeros:
[ banana TO laranja ] = banana,casa, dado
[ 100 TO 110 ] = 100,101,102,..,110 - { TO } idem ao colchetes, porém não inclui os itens especificados:
{ 100 to 110 } = 101,..,109 - + (mais) indica que a palavra é requerida. Util apenas quando utilizado com o OR : "+unix windows" = frases que PRECISAM ter "unix" mas não necessáriamente "windows".
- () agrupa condições: '(unix OR windows) AND macOS'
- : utilizado para indentificar TAGs em pesquisa de campos com conteúdo XML:
'nome:cesar' = TAGs nome que contem palavra cesar. - AND &&
- OR ||;
- NOT - !
- () Para agrupar
- "" (aspas) pesquisa por uma frase exata
- \\ (escape)
Sintaxe básica
Para realizar uma pesquisa com BTS , utiliza-se apenas uma unica função:
bts_contains ( <coluna>, '<string_pesquisa>' [ , score # REAL] )
<coluna> : Nome da coluna que existe o indice
<string_pesquisa> : String de pesquisa
[,<var> # REAL] : Define uma SVL (Statment local variable) que irá
retornar um valor de 0.0 a 100.0
Exemplos
SELECT ... WHERE bts_contains( nome , 'joao and maria' ); SELECT ... WHERE bts_contains( nome , 'joao && maria' ); SELECT ... WHERE bts_contains( nome , 'cesar~' ); SELECT escore,... WHERE bts_contains( nome , 'fernand?', escore # REAL ); SELECT ... WHERE bts_contains( nome , '( cesar or mauricio) and martins' ); SELECT ... WHERE bts_contains( nome , '"cesar marts"~3' ); SELECT ... WHERE bts_contains( descricao , 'informix and -oracle' ); SELECT ... WHERE bts_contains( descricao , 'informix and not oracle' ); SELECT ... WHERE bts_contains( descricao , 'informix and !oracle' ); SELECT ... WHERE bts_contains( descricao , 'ids and 11.50 ' );
Limitações
- Até a versão 1.20 não suporta Enterprise Replication e nenhuma configuração do MACH 11.
- Não suporta SQLs Distribudos (tabelas de varios bancos no mesmo SQL)
- Não utiliza recursos de PDQ ( Parallel Database Query)
- Não suporta caracteres baseado em ideogramas como Chines, Japones, Koreano, etc.
- Dependendo do modo como o indice é criado é necessário programar rotinas para compactar o indice (remover registros deletados).
- Qualquer modificação no campo que contem o indice, todo indice é travado (lock). Isso faz com que a concorrência se torne um problema.
Observação: Apesar da informação acima ter sido tirado do manual, no teste prático isso não ocorreu. Quando foi feito um lock exclusivo em cada linha da tabela nos (alterando o campo que contem o BTS), todos executaram sem problemas. O banco colocou apenas um lock de byte no registro: HDR+B - Até a versão 1.10 (distribuida com Informix versão até 11.50 UC2) :
- Devido o indice ser gravado em um dbspace externo (extspace) o backup não é realizado junto com o do banco.
- Por o indice ser gravado em um dbspace externo (extspace) o I/O é feito a nivel de File System. Assim não há ganho de performance igual RAW DEVICES
Exemplo
### Se utilizado versão 1.10 ou anterior, abaixo segue comandos para criar EXTSPACE $ mkdir /IFMX_DADOS/ids_chunks/bts.ch1 ; $ onspaces -c -x bts_extspace -p /IFMX_DADOS/ids_chunks/bts.ch1 ; ## Criar indice do BTS CREATE INDEX ixATags on t_tags (nome bts_char_ops) using bts(delete="deferred") in bts_extspace ; ## Realizar seleção nos dados SELECT escore, nome FROM t_tags WHERE bts_contains(nome, 'DML OR DDL', escore # REAL); SELECT * from sysmaster:sysextspace ;
Utilizando BTS
Operadores de tipo de dados para o Create Index:
Data Type Operator Class BLOB bts_blob_ops CHAR bts_char_ops CLOB bts_clob_ops LVARCHAR bts_lvarchar_ops NCHAR bts_nchar_ops NVARCHAR bts_nvarchar_ops VARCHAR bts_varchar_ops
Observação
Qualquer pontuação especificada no campo de pesquisa é ignorado
Definindo Stopwords
- Pode-se definir de três maneiras (passado como parametro no CREATE INDEX):
inline como parametro do CREATE INDEX, arquivo externo ou conteudo de uma tabela - ATENÇÃO: Estes parametros só serão lido uma vez, durante a criação do indice.
Se forem modificado, para ter efeito sobre um indice, é necessário recria-lo. - Quando utilizado arquivo texto ou tabela, cada "stopword" pode ser separada por virgula, espaço ou quebra de linha. Pode mesclar o uso dos separadores.
- Se não for especificado é utilizado uma lista padrão de "stopwords" para ligua inglesa (a an and are as at be ...).
CREATE INDEX ixATags on t_tags (nome bts_char_ops) using
bts(delete="deferred", stopwords="(no,de,eu,para)") in bts_extspace ;
CREATE INDEX ixATags on t_tags (nome bts_char_ops) using
bts(delete="deferred", stopwords="file:/tmp/stopwords.txt") in bts_extspace;
CREATE INDEX ixATags on t_tags (nome bts_char_ops) using
bts(delete="deferred",stopwords="table:tab_stopw.colxyz") in bts_extspace;
Definindo modo de deleção
Existe dois modos de trabalhar com exclusão de dados no indice, estas opções são definidas na criação do indice:
- deferred: é a opção padrão. Ela não exclui o dado , apenas flega a linha dizendo que o dado foi excluido. Para remover fisicamente o dado é necessário executar um processo manual (bts_index_compact ou oncheck)
- immediate: Faz com que o dado seja excluido fisicamente no momento da exclusão automaticamente. Isso evita que seja necessário execução de processos extras para manutenção do indice.
Trabalhando com XML
- Campos que possuem XML podem ser interpretados pelo BTS.
- Os atributos de um XML , por default não são indexados, apenas o texto, ver parametro xmlinclude_contents.
- Para que um texto seja interpretado com XML e assim evitar que as TAGs sejam indexadas sem necessidade é necessário utilizar no minimo um dos parametros: xmltags ou all_xmltags, os demais parametros são opcionais, são eles:
- xmltags
Indexa um ou mais TAGs especificadas. Podem ser especificadas atraves de parametro "inline",arquivo ou tabela (igual aos parametros do stopwords acima) - all_xmltags
[yes/no] Indexa todas as TAGs - xmlpath_processing
[yes/no] Habilita pesquisa baseada em "full" ou "relative" path XML.
Exemplo: /text/book/title , /text/book/author, /text/book/date , text/book/title , book/author,date - include_namespaces
[yes/no] Quando a TAG de um XML utiliza padrão de namespaces (prefixo:local) na definição da TAG é possível forçar a criação do indice com o namespace. Caso não seja utilizado esta opção o prefixo será removido (ver exemplos). - include_subtag_text
[yes/no] Indexa o conteudo das subtags junto com as tags, na mesma linha. Quando este parametro não é informado o valor padrão é "no", desta maneira se dentro do texto do XML possuir um texto com tags HTML, o conteudo de cada TAG é indexado separadamente. Com este parametro ativado todo o texto é indexado junto em uma unica linha e as TAGs de HTML são removidas. - include_contents
[yes/no] Cria um campo no indice chamado "contents" e nele inclui TODAS as TAGs (independente do parametro xmltags ou all_xmltags), permitindo pesquisar assim por todos os textos existentes igual a um texto não classificado como XML(atributos,tag e texto).
Este parametro é util para flexibilizar a pesquisa, permitindo pesquisar por uma TAG especifica ou por todo o texto do XML. - strip_xmltags
[yes/no] Pega o conteudo de TODAS das TAGs de um XML , extrai apenas o conteudo e põe tudo em um campo no indice chamado "contents". É similar ao include_contents, porém não inclui as tags e atributos.
EXCEÇÃO: Este parametro pode ser utilizado com ou sem o xmltags e all_xmltags.
- xmltags
Observações
- ATENÇÃO: TAGs XML diferenciam Maiuscula/Minuscula (case sensitive). Quando as tags são passadas no xmltags através de parametro "inline" elas são automaticamente convertidas para caixa baixa (lower case), portanto se o XML possuir TAGs com letras maiusculas é obrigatório utilizar o arquivo externo ou tabela para especificar as TAGs.
- Conforme testes, Cuidado quando utilizado o parametro xmlpath_processing, ele é não tão flexivel quanto parece no manual. Quando especificado com o parametro all_xmltags todas as tags são criadas com "full path" e assim devem ser pesquisadas, se especificado com parametro xmltags, permite no maximo que as TAGs sejam especificadas através de "full" ou "relative" path.
- Quando utilizado o parametro include_contents e o campo "contents" é criado no indice, se na pesquisa com o bts_contains não for especificado o nome da TAG ou path completo, a pesquisa é realizada no campo "contents", desta maneira a função se comporta como se estivesse pesquisando em um arquivo texto normal
- Quando utilizado o parametro include_contents lembrar de considerar que o espaço utilizado pelo indice será praticamente dobrado.
Exemplos
EXECUTE PROCEDURE IFX_ALLOW_NEWLINE('t');
CREATE TABLE boats(docid integer, xml_data lvarchar(4096));
INSERT INTO boats values(1, "
<boat>
<nome sobrenome='inacio'>cesar</nome>
<skipper>Captain Jack</skipper>
<boatname>Black Pearl</boatname>
</boat> ");
INSERT INTO boats values(2, "
<boat>
<nome sobrenome='alexandre'>rodrigo</nome>
<skipper>Captain Black</skipper>
<boatname>The Queen Anne's Revenge</boatname>
</boat> ");
-- XMLTAGS
CREATE INDEX boats_bts ON boats(xml_data bts_lvarchar_ops)
USING bts(xmltags="(skipper,boatname)") IN bts_extspace;
-- Este select irá retornar apenas a linha docid=2
SELECT xml_data FROM boats WHERE bts_contains(xml_data, 'skipper:black');
-- XMLPATH_PROCESSING
CREATE INDEX boats2_bts ON boats(xml_data bts_lvarchar_ops)
USING bts(all_xmltags="yes",xmlpath_processing="yes") IN bts_extspace;
-- Este select irá retornar apenas a linha docid=2
SELECT xml_data FROM boats WHERE bts_contains(xml_data,'/boat/skipper:black');
-- INCLUDE_CONTENTS
CREATE INDEX boats3_bts ON boats(xml_data bts_lvarchar_ops)
USING bts(all_xmltags="yes",xmlpath_processing="yes",include_contents="yes")
IN bts_extspace;
-- Este select irá retornar apenas a linha docid=1
SELECT xml_data FROM boats WHERE bts_contains(xml_data, 'contents:inacio');
-- Este select irá retornar apenas a linha docid=1 e 2
SELECT xml_data FROM boats WHERE bts_contains(xml_data, 'contents:sobrenome');
-- INCLUDE_NAMESPACES
-- Suponde que as TAGs skipper dos XMLs sejam:
-- <boat:skipper>Captain Black</boat:skipper>
CREATE INDEX boats2_bts ON boats(xml_data bts_lvarchar_ops)
USING bts(all_xmltags="yes",xmlpath_processing="yes",include_namespaces="yes"
) IN bts_extspace;
-- com include_namespaces
SELECT xml_data FROM boats WHERE bts_contains(xml_data,
'/boat/boat\\:skipper:inacio');
-- sem include_namespaces
SELECT xml_data FROM boats WHERE bts_contains(xml_data,
'/boat/skipper:inacio');
-- INCLUDE_SUBTAGS_TEXT
-- Suponde que a TAG nome do registro DOCID 1 seja alterado para:
-- <nome>Cesar <super_negrito>Martins</super_negrito></nome>
CREATE INDEX boats2_bts ON boats(xml_data bts_lvarchar_ops)
USING bts(all_xmltags="yes",xmlpath_processing="yes",
include_subtags_text="yes" ) IN bts_extspace;
-- com include_subtags_text="no" (padrao)
-- Este select não irá retornar nenhuma linha
SELECT xml_data FROM boats WHERE bts_contains(xml_data,
'/boat/nome:"cesar && martins"');
-- com include_subtags_text="yes"
-- Este select irá retornar docid=1
SELECT xml_data FROM boats WHERE bts_contains(xml_data,
'/boat/nome:"cesar && martins"');
Funções
Observação: (versão 1.10 ou anterior) As sintaxes abaixo foram copiadas do manual, porém nos testes práticos houve uma diferença quando passado o parametro "extspace/.../index_name". Se trabalhado conforme o manual a função retorna erro de o indice não existe, para contornar basta informar apenas o nome do indice: bts_index_fields('idxTabelaZ');
- bts_index_compact ( ' extspace / db_name / owner_name / index_name ' ) return 't'/'f'
Compacta o indice excluindo fiscamente os registros flegados como apagados. Os resgistros são flegados como apagado apenas quando o indice é criado com a opção "delete='deferred'" (padrão).
A execução deste processo também pode ser realizada através do oncheck:oncheck -ci -y db_name:table_name#index_name - bts_index_fields ( ' extspace / db_name / owner_name / index_name ' )
Exibe os campos indexados, util apenas quando indexado TAGs XML. Se o indice criado não for XML irá retornar apenas um campo: "contents".
Util para identificar o path de TAGs. - bts_release()
Retorna a versão do BTS, por exemplo: BTS 1.10 Compiled on Wed Apr 23 23:49:29 CDT 2008 - bts_tracefile( filename )
Utilizado para debugar a utilização do BTS. Deve-se informar o path "FULL" do arquivo. O arquivo será sempre incrementado e deverá ter permissão de gravação para o usuário informix. Se não for informado nome do arquivo o log será gravado no $INFORMIXDIR/tmp com o nome <session_id>.trc
Usar em conjunto com o bts_tracelevel. - bts_tracelevel( level )
Define o nivel de debug.
Level 1 UDR entry points. 10 UDR entry points and lower level calls. 20 Trace information and small events. 100 Memory resource tracing (very verbose).
Recomendações
- Sempre considerar utilizar os seguintes parametros para campos que possuem
XML: xmlpath_processing,include_subtag_text,include_contents
- Campos que são modificados com alta frequencia, utilizar delete="deferred"
- Campos que são modificados com baixa frequencia, utilizar delete="immediate"
- Criar rotina automatica para compactação dos indices
- Prestar atenção na performance de I/O de onde será salvo o EXTSPACE
- Lembrar que as pesquisas com BTS são sempre DIRTY READ.
- Lembrar que a administração do EXTSPACE requer um trabalho a mais.
- Nos testes realizados com a versão 1.10 , evitar utilizar a função de pesquisa bts_contains com querys muito complexas pois ainda há muito bugs em situações como essa.
- 477 leituras
Tags:





Comentar