Solucionado (ver solução)
Solucionado
(ver solução)
9
respostas

Ignorando um atributo na pesquisa

Olá, é possível ele não fazer a busca em determinado atributo? Coloquei para não mapear o _all dentro de mappings e também no campo em específico, mas mesmo assim ele busca.

9 respostas

Oi Rafael!

Mostra aqui por favor como está o mappings que fez e a busca que está fazendo pra ficar mais fácil de encontrar o que está falhando. :)

Oi Ana! Consegui fazer para que o campo não apareça na busca, porém não estou conseguindo fazer o que eu quero. Sou novo e com muitas dúvidas e dificuldades.

{
  "settings": {
    "index": {
      "number_of_shards": 3,
      "number_of_replicas": 0
    },
    "analysis": {
      "filter": {
        "brazilian_stop": {
          "type": "stop",
          "stopwords": "_brazilian_"
        },
        "brazilian_stemmer": {
          "type": "stemmer",
          "language": "brazilian"
        },
        "filtro_de_sinonimos": {
          "type": "synonym",
          "synonyms": [
            "sao => são",
            "são+paulo=> sao+paulo",
            "são,sao"
          ]
        }
      },
      "analyzer": {
        "sinonimos": {
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "brazilian_stop",
            "brazilian_stemmer",
            "filtro_de_sinonimos"
          ]
        }
      }
    }
  },
  "mappings": {
    "busca": {
      "properties": {
        "company": {
          "type": "string",
          "index": "not_analyzed"
        },
        "address_1": {
          "type": "string",
          "index": "analyzed",
          "analyzer": "brazilian"
        },
        "address_2": {
          "type": "string",
          "index": "analyzed",
          "analyzer": "brazilian"
        },
        "number": {
          "type": "string",
          "index": "not_analyzed"
        },
        "complemento": {
          "type": "string",
          "index": "not_analyzed"
        },
        "city": {
          "type": "string",
          "index": "analyzed",
          "analyzer": "brazilian",
          "search_analyzer": "sinonimos"
        },
        "postcode": {
          "type": "string",
          "index": "not_analyzed"
        },
        "lat": {
          "type": "string",
          "index": "not_analyzed"
        },
        "lng": {
          "type": "string",
          "index": "not_analyzed"
        },
        "razao_social": {
          "type": "string",
          "index": "not_analyzed"
        },
        "nome_fantasia": {
          "type": "string",
          "index": "analyzed",
          "analyzer": "brazilian"
        },
        "descricao_empresa": {
          "type": "string",
          "index": "no"
        },
        "nome": {
          "type": "string",
          "index": "analyzed",
          "analyzer": "brazilian"
        }
      }
    }
  }
}

O que eu fiz foi retirar o "_all" e no campo que não queria que aparecesse na busca coloquei "no" no índice. Como pode ver no código Ana, estou perdido. Quero buscar por 'são paulo', por exemplo, e me retorna 68 casos, quando busco por 'sao paulo' só vem 1. Além de outros problemas, não sei mais o que faço, como disse, estou com dificuldades para entender, consegue me ajudar?

Olá Rafael,

O que está descrito no final onde você quer procurar sao paulo e são paulo é bem fácil de resolver, contudo, não esta claro para mim o problema original que esta tentando resolver.

Poderia definir claramente o problema ao invés do que está tentando fazer para resolve-lo? Desse modo fica mais fácil de te ajudar.

Olá Thadeu,

O que quero fazer é uma busca em mais de um campo, em mais de um 'atributo'. Por exemplo 'restaurante sao paulo' ou 'restaurante sao paulo', 'tênis azul masculino 40', 'bola de futebol', 'blusinha regata rosa', não sei, qualquer busca simples para o elasticsearch... Não sei se é uma boa prática, creio que não, mas eu consegui fazer utilizando uma querie que só mudo o que quero localizar. Essa 'configuração' não estava funcionando, pois na hora de utilizar os comandos rest eu estava utilizando o kopf, utilizei o sense e funcionou... O que quero fazer é uma busca onde ele busque independente de plural ou singular, masculino ou feminino, sinônimos (isso eu terei de adicionar e aperfeiçoar com o tempo), em diversos campos e principalmente que ignore a busca em outros (adicionei index = no para esses casos). Desculpa se não estou sendo muito claro ou específico, mas consegui fazer e queria saber se é correto.

solução!

Vou quebrar a resposta em algumas partes para facilitar o entendimento.

"O que quero fazer é uma busca onde ele busque independente de plural ou singular, masculino ou feminino, sinônimos (isso eu terei de adicionar e aperfeiçoar com o tempo)"

Como você está utilizando português apenas, eu começaria utilizando o analyzer portuguese assim como fizemos no curso. Você consegue usar a api _analyze para ver as entradas que serão geradas no índice invertido. Isso é suficiente para te convencer que plurais, masculino e feminino vai funcionar. Sugiro fortemente fazer uns bons testes apenas com estas condições em um único campo. Isso não é seu objetivo final, mas vai te ajudar a separar os problemas.

"O que quero fazer é uma busca em mais de um campo, em mais de um 'atributo'. Por exemplo 'restaurante sao paulo' ou 'restaurante sao paulo', 'tênis azul masculino 40', 'bola de futebol', 'blusinha regata rosa', não sei, qualquer busca simples para o elasticsearch.."

Só para ver se eu entendo. Você quer poder jogar todos os termos e procurar no documento inteiro, salvo alguns campos. No caso, você teria um documento onde restaurante esta em um campo, sao paulo esta em outro, etc. É isso? Se for, o que você tem duas opções. A primeira é deixar a busca ir no campo _all. A ideia de excluir atributos que não são relevantes para qualquer busca que vai fazer no campo _all é boa. O que falta no seu mapping é utilizar o analyzer portuguese para o campo _all (nós fizemos isso no curso).

A segunda ideia é você enviar a busca para todos os atributos que quer considerar. Se a lista de atributos for pequena, vale a pena pois você não sacrifica o campo _all. Se a lista for grande, use a ideia acima.

Em resumo:

0- Simule a análise de textos com o analyzer portuguese

1- Crie o indice com o analyzer portuguese no campo _all. Não coloque sinômimo algum já que seu caso de uso não parece precisar de sinônimos. Considere excluir alguns atributos do campo _all se a quantidade de atributos for muito pequena (limite a 10% do seus seus atributos)

2- Adicione alguns registros no índice e execute suas buscas para confirmar o resultado.

3- Teste suas buscas sem especificar atributo e veja o resultado.

Boa sorte.

Oi Thadeu, Utilizei a api _analyze portuguese e testei 'são paulo', mas ela retorna somente 'paul', não é gerado o token para são. Como testei brazilian e deu certo, mudei para ele. Sabe me informar se portuguese é 'melhor', 'mais completo' que brazilian? Não quero mapear todos os campos, pois em alguns tem textos que não são importantes para a busca. Se fosse mapeado, atrapalharia no resultado. Nesse meu caso que é ao contrário, eu tenho mais campos para serem excluídos do que incluídos na busca, qual é a melhor abordagem? Digamos que de 40, eu só utilizei 5

{
  "settings": {
    "index": {
      "number_of_shards": 3,
      "number_of_replicas": 0
    },
    "analysis": {
      "filter": {
        "brazilian_stop": {
          "type": "stop",
          "stopwords": "_brazilian_"
        },
        "brazilian_stemmer": {
          "type": "stemmer",
          "language": "brazilian"
        },
        "filtro_de_sinonimos": {
          "type": "synonym",
          "synonyms": [
            "r,rua",
            "av,aven",
            "educ => escol"
          ]
        }
      },
      "analyzer": {
        "sinonimos": {
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "brazilian_stop",
            "brazilian_stemmer",
            "filtro_de_sinonimos"
          ]
        }
      }
    }
  },
  "mappings": {
    "busca": {
      "_all": {
        "type": "string",
          "index": "analyzed",
          "analyzer": "brazilian",
          "search_analyzer": "sinonimos"
      },
      "properties": {
        "address_1": {
          "type": "string",
          "index": "analyzed",
          "analyzer": "brazilian",
          "search_analyzer": "sinonimos"
        },
        "address_2": {
          "type": "string",
          "index": "analyzed",
          "analyzer": "brazilian",
          "search_analyzer": "sinonimos"
        },
        "address_id": {
          "type": "long",
          "index": "no"
        },
...
          "type": "string",
          "index": "no"
        },
        "zone_id": {
          "type": "long",
          "index": "no"
        }
      }
    }
  }
}

Eu testei desse jeito e funcionou, o resultado só não foi 100%, pois existem algumas buscas que tenho que colocar sinônimos, mas no geral ficou bom.

Oi Rafael,

Brazilian é novo para mim, obrigado por compartilhar :). Que bom que funcionou melhor e, como eu havia te falado, ia te resolver boa parte dos problemas. Use os sinônimos com cuidado para não ter resultados inesperados. Pense em sinônimos como ajuste fino. No curso eu fui passo a passo nos cuidados que temos que ter com sinônimos. De uma revisada e tenho certeza que vai fazer um ótimo trabalho.

Sobre sua busca, se vai querer que a busca deve acontecer em 5 de 40 campos (12.5%) você tem as seguintes opções:

1- Se jamais foi fazer buscas nos demais campos sem especifica-los, pode considerar mexer no campo _all. Assim você manda as queries direto para o elasticsearch e não precisa se preocupar em indicar os campos. O problema que eu vejo é que, um mês depois você não vai lembrar quais são os campos.

2- (Recomendada) Exponha uma API e faça a busca nos 5 campos que precisa. Desse modo você é mais explícito. Não creio que vai ter perda de desempenho no tempo de execução da consulta. Veja este link para saber como fazê-lo https://www.elastic.co/guide/en/elasticsearch/guide/current/multi-query-strings.html.

Obrigado Thadeu! Sou novo e inexperiente nisso, mas qual é a abordagem de uma Centauro, Submarino, por exemplo? Eu só digito o que quero e a busca vai nos campos que eu não faço nem idéia e nem preciso. Tem uma API por trás disso? Não faço ideia de como fazer, tenho e vou estudar muito! Desculpa a pergunta 'idiota'.

Oi Rafael,

Eu não tenho certeza como eles fazem do ponto de vista de indexação de dados, mas posso dizer como eu faria :)

Eu colocaria no elasticsearch apenas os atributos que te interessam para sua busca e usaria um analisador como o brazilian que você usou no campo _all. Você deve mostrar estes resultados no site. Os atributos que não te interessam na busca ficariam, ou em outro índice ou em um banco de dados (seja sql ou nosql separado). Você poderia buscar detalhes dos produtos que foram selecionados neste banco no momento do fechamento da compra.

Quanto a API, pensa q você vai ter um website que faz uma chamada a um servidor web (API no website para onde você manda a requisição http - e.g.: /procura?q=). O seu servidor web fará a chamada ao Elasticsearch. A chamada do servidor web para o Elasticsearch é o local onde você transforma o que esta escrito em em algo que faça sentido para o Elasticsearch. É este o momento em que você usa o link que te mandei no post anterior.

Se esta com dúvidas em relação a arquiteturas web, sugiro dar uma olhada nos cursos disponíveis na Alura. Estudar sempre é preciso :)

Bons estudos.