RavenDB consegue falar português

RavenDB utiliza Lucene como motor de indexação. Isso significa suporte natural a full-text search que pode ser facilmente habilitado a partir da definição de um índice como o que segue.


public class Products_SearchByName : AbstractIndexCreationTask<Product>
{
    public Products_SearchByName()
    {
        Map = products =>
            from p in products
            select new
            {
                p.Name
            };

        Index(entry => entry.Name, FieldIndexing.Analyzed);
    }
}

Como inidicado no código, o campo Name está marcado como Analyzed.

Analyzed?

Quando um campo é marcado como analyzed, isso indica que seu conteúdo será quebrado em termos. São esses termos que serão considerados no momento de uma busca.


No banco de dados de exemplo Northwind, há um produto cadastrado chamado “Guaraná Fantásica” (um claro representante brasileiro). Por default, RavenDB irá gerar dois termos para essa string: 1) “guaraná” e 2) “fantástica”. Ou seja, cada palavra da string, convertida para minúsculo é considerada como um termo de busca.

Compatibilidade nativa com o inglês

O processo de análise padrão do RavenDB otimiza o processo de geração de termos para atender as regras da língua inglêsa. Palavras vazias (stop words) são ignoradas automaticamente. Além disso, “Mario’s” gera “Mario”, a abreviação “F.Y.I.” gera “FYI”.

No momento em que ocorre uma busca, a string buscada também passa por essa análise. O resultado é que as chances de encontrar o que está sendo buscado cresce (mesmo que o que esteja salvo no banco esteja escrito de forma diferente daquela que está sendo usada no momento da consulta).

Tropicalizando o RavenDB

O processo de geração de termos pode ser muito mais interessante para nós, aqui do Brasil, se este considerar particularidades do nosso idioma. Por exemplo, a geração de termos poderia remover acentos das palavras (para que o usuário possa procurar tanto “guaraná” quanto “guarana”). Além disso, deveria considerar o conjunto de palavras vazias da língua portuguesa (de, da, o, a, …).

A customização do processo de análise do RavenDB ocorre pela escrita de um analisador customizado. Há uma implementação completa no meu Github.

Para escrever esse analisador, parti do código do próprio RavenDB aplicando modificações onde eram convenientes.

Show me the code!

Embora exista um bocado de “Lucene” no código que segue, acho que ele é claro o suficiente para indicar o que estou fazendo.


using System;
using System.IO;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Analysis.Tokenattributes;

namespace RavenDB.Indexing.BrazilianAnalyzer
{
    public sealed class RavenBrazilianFilter : TokenFilter
    {
        public static string[] BRAZILIAN_STOP_WORDS = {
            "a","ainda","alem","ambas","ambos","antes",
            "ao","aonde","aos","apos","aquele","aqueles",
            "as","assim","com","como","contra","contudo",
            "cuja","cujas","cujo","cujos","da","das","de",
            "dela","dele","deles","demais","depois","desde",
            "desta","deste","dispoe","dispoem","diversa",
            "diversas","diversos","do","dos","durante","e",
            "ela","elas","ele","eles","em","entao","entre",
            "essa","essas","esse","esses","esta","estas",
            "este","estes","ha","isso","isto","logo","mais",
            "mas","mediante","menos","mesma","mesmas","mesmo",
            "mesmos","na","nas","nao","nas","nem","nesse","neste",
            "nos","o","os","ou","outra","outras","outro","outros",
            "pelas","pelas","pelo","pelos","perante","pois","por",
            "porque","portanto","proprio","proprios","quais","qual",
            "qualquer","quando","quanto","que","quem","quer","se",
            "seja","sem","sendo","seu","seus","sob","sobre","sua",
            "suas","tal","tambem","teu","teus","toda","todas","todo",
            "todos","tua","tuas","tudo","um","uma","umas","uns"
        };

        private readonly TokenStream _innerInputStream;
        private readonly ITermAttribute _termAtt;
        private readonly ITypeAttribute _typeAtt;
        
        private const string AcronymType = "<ACRONYM>";
        private readonly CharArraySet _stopWords = new CharArraySet(BRAZILIAN_STOP_WORDS, false);

        public RavenBrazilianFilter(TokenStream input) : base(input)
        {
            _innerInputStream = input;
            _termAtt = AddAttribute<ITermAttribute>();
            _typeAtt = AddAttribute<ITypeAttribute>();
        }

        public override bool IncrementToken()
        {
            if (!input.IncrementToken())
            {
                return false;
            }

            var buffer = _termAtt.TermBuffer();
            var bufferLength = _termAtt.TermLength();
            var type = _typeAtt.Type;

            var bufferUpdated = true;

            if (type == AcronymType)
            {
                // remove dots
                var upto = 0;
                for (int i = 0; i < bufferLength; i++)
                {
                    var c = buffer[i];
                    if (c != '.')
                        buffer[upto++] = CharUtils.ToLower(c);
                }
                _termAtt.SetTermLength(upto);
            }
            else
            {
                do
                {
                    //If we consumed a stop word we need to update the buffer and its length.
                    if (!bufferUpdated)
                    {
                        bufferLength = _termAtt.TermLength();
                        buffer = _termAtt.TermBuffer();
                    }

                    for (var i = 0; i < bufferLength; i++)
                    {
                        buffer[i] = CharUtils.RemoveAccentMark(CharUtils.ToLower(buffer[i]));
                    }

                    if (!_stopWords.Contains(buffer, 0, bufferLength))
                    {
                        return true;
                    }

                    bufferUpdated = false;
                } while (input.IncrementToken());

                return false;
            }
            return true;
        }

        internal bool Reset(TextReader reader)
        {
            var input = _innerInputStream as StandardTokenizer;

            if (input == null) return false;

            input.Reset(reader);
            return true;
        }
    }
}

Adeus acentos!

Como usar o analisador customizado

É importante ter o analisador em uma DLL que possa ser adicionada ao servidor do RavenDB (conforme indicado na documentação). Se você optar por utilizar o analisar que escrevi, basta compilar o projeto para obter um assembly pronto.

Para usar um analisador customizado, basta adicionar a DLL com o analisador em uma pasta chamada “Analyzers” no diretório onde está o servidor do RavenDB e modificar o índice indicando que analisador deverá ser utilizado.


public class Products_SearchByName : AbstractIndexCreationTask<Product>
{
    public Products_SearchByName()
    {
        Map = products =>
            from p in products
            select new
            {
                p.Name
            };

        Index(entry => entry.Name, FieldIndexing.Analyzed);
        Analyze(entry => entry.Name, typeof(RavenBrazilianAnalyzer).AssemblyQualifiedName);
    }
}

Esse novo índice removerá acentos nos termos gerados.

Dessa forma, a seguinte busca retornará o produto sem problemas.


class Program
{
    static void Main(string[] args)
    {
        using (var session = DocumentStoreHolder.Store.OpenSession())
        {
            var results = session
                .Query<Product, Products_SearchByName>()
                .Search(r => r.Name, "guarana")
                .ToList();

            foreach (var result in results)
            {
                Console.WriteLine(result.Name);
            }
        }
    }
}

Afinal a palavra informada está na lista de termos.

Compartilhe este insight:

Elemar Júnior

Sou fundador e CEO da EximiaCo e atuo como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Elemar Júnior

Sou fundador e CEO da EximiaCo e atuo como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Mais insights para o seu negócio

Veja mais alguns estudos e reflexões que podem gerar alguns insights para o seu negócio:

Expressões regulares são fantásticas. Entretanto, precisam ser utilizadas com moderação pois podem impactar de forma perceptível a performance. A expressão...
Nesse ano, palestrei na APIX sobre microsserviços. Abaixo, registro em vídeo feito pela organização do evento. Comentários? Feedback?
Empresas modernas, com estilo de gestão diferente e resultados espetaculares, estão desafiando tudo o que sabemos sobre estratégia e execução....
As a consultant, I often need to work with the code that I do not know. I need to understand...
So, I decided to learn how to code using R. That’s something I wrote: ## defining a function makeCacheMatrix <-...
O passatempo da minha adolescência era jogar Xadrez. Simplesmente amava o jogo. Em algumas partidas, fui brilhante. No geral, fui...

Curso Reputação e Marketing Pessoal

Masterclasses

01

Introdução do curso

02

Por que sua “reputação” é importante?

03

Como você se apresenta?

04

Como você apresenta suas ideias?

05

Como usar Storytelling?

06

Você tem uma dor? Eu tenho o alívio!

07

Escrita efetiva para não escritores

08

Como aumentar (e manter) sua audiência?

09

Gatilhos! Gatilhos!

10

Triple Threat: Domine Produto, Embalagem e Distribuição

11

Estratégias Vencedoras: Desbloqueie o Poder da Teoria dos Jogos

12

Análise SWOT de sua marca pessoal

13

Soterrado por informações? Aprenda a fazer gestão do conhecimento pessoal, do jeito certo

14

Vendo além do óbvio com a Pentad de Burkle

15

Construindo Reputação através de Métricas: A Arte de Alinhar Expectativas com Lag e Lead Measures

16

A Tríade da Liderança: Navegando entre Líder, Liderado e Contexto no Mundo do Marketing Pessoal

17

Análise PESTEL para Marketing Pessoal

18

Canvas de Proposta de Valor para Marca Pessoal

19

Método OKR para Objetivos Pessoais

20

Análise de Competências de Gallup

21

Feedback 360 Graus para Autoavaliação

22

Modelo de Cinco Forças de Porter

23

Estratégia Blue Ocean para Diferenciação Pessoal

24

Análise de Tendências para Previsão de Mercado

25

Design Thinking para Inovação Pessoal

26

Metodologia Agile para Desenvolvimento Pessoal

27

Análise de Redes Sociais para Ampliar Conexões

Lições complementares

28

Apresentando-se do Jeito Certo

29

O mercado remunera raridade? Como evidenciar a sua?

30

O que pode estar te impedindo de ter sucesso

Recomendações de Leituras

31

Aprendendo a qualificar sua reputação do jeito certo

32

Quem é você?

33

Qual a sua “IDEIA”?

34

StoryTelling

35

Você tem uma dor? Eu tenho o alívio!

36

Escrita efetiva para não escritores

37

Gatilhos!

38

Triple Threat: Domine Produto, Embalagem e Distribuição

39

Estratégias Vencedoras: Desbloqueie o Poder da Teoria do Jogos

40

Análise SWOT de sua marca pessoal

Inscrição realizada com sucesso!

No dia da masterclass você receberá um e-mail com um link para acompanhar a aula ao vivo. Até lá!

A sua subscrição foi enviada com sucesso!

Aguarde, em breve entraremos em contato com você para lhe fornecer mais informações sobre como participar da mentoria.

Crie sua conta

Preencha os dados para iniciar o seu cadastro no plano anual do Clube de Estudos:

Crie sua conta

Preencha os dados para iniciar o seu cadastro no plano mensal do Clube de Estudos:

× Precisa de ajuda?