<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[ES|QL - Elasticsearch Labs]]></title>
    <description><![CDATA[Articles and tutorials from the Search team at Elastic]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[ES|QL - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/pt/search-labs/blog/category/esql</link>
    </image>
    <link>https://www.elastic.co/pt/search-labs/blog/category/esql</link>
    <atom:link href="https://www.elastic.co/pt/search-labs/rss/category/esql.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[pt]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 15:08:05 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Elasticsearch ES|QL traz busca de texto completo para dados que você nunca indexou]]></title>
    <description><![CDATA[MATCH e TO_TEXT trazem busca de texto completo para dados que você nunca indexou. Buscar colunas computadas, campos não mapeados e fontes federadas em ES|QL.]]></description>
    <content:encoded><![CDATA[<p>ES|QL MATCH agora executa busca de texto completo em dados que você nunca indexou. Colunas computadas, campos não mapeados, strings montadas em tempo real e até dados federados no S3. A nova função TO_TEXT diz ao ES|QL que trate qualquer string como texto analisável, para que MATCH possa tokenizar, normalizar maiúsculas e minúsculas, e fazer correspondência de termos em valores que existem somente durante a vida útil de uma consulta. Isso vai além da correspondência por padrões com LIKE e RLIKE que a maioria dos mecanismos de consulta oferece para strings não indexadas: é análise de verdade. Já disponível no Elastic Cloud Serverless e como prévia técnica no Elasticsearch 9.5.</p><h2>Como o MATCH e TO_TEXT habilitam a busca de texto completo em qualquer expressão ES|QL</h2><p>Vamos começar com uma consulta que era impossível no Elasticsearch 9.4, que usa <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/eval">o comando EVAL</a>:</p><p>Neste exemplo, resumo não possui mapeamento ou configuração de analisador. Também não está associado a nenhum índice invertido. Ele existe apenas durante a vida útil dessa consulta, mas agora você pode buscar mesmo assim. Duas adições fazem isso funcionar.</p><p>Primeiro, <a href="https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/search-functions/match">MATCH</a> agora aceita qualquer expressão como seu primeiro argumento, não apenas um campo mapeado. Isso inclui colunas produzidas pelo EVAL e resultados de funções usados em linha. Também inclui campos não mapeados carregados diretamente do documento original. Além disso, todos os tipos de dados normalmente aceitos pelo MATCH são suportados neste novo caso de uso.</p><p>A segunda parte disso é a nova <a href="https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/type-conversion-functions/to_text">função TO_TEXT</a>, que é a primeira função de conversão ES|QL que produz saída do tipo texto. Até agora, colunas de texto só podiam vir de campos mapeados indexados, e todas as strings produzidas pelas expressões ES|QL eram valores de palavras-chave em vez de texto. A distinção importa porque o MATCH trata os dois de forma diferente: os valores do texto são analisados, enquanto os valores das palavras-chave são comparados exatamente, espelhando como uma consulta MATCH em um campo indexado se reescreve para uma consulta de termo. TO_TEXT(x) é como você diz ao ES|QL: <em>trate essa sequência como texto completo</em>.</p><p>Este é incluído como uma prévia técnica no Elasticsearch 9.5 e, por isso, possui algumas limitações:</p><ul><li><p>No momento, funciona apenas para filtragem. Um MATCH em uma expressão ainda não contribui para a pontuação de relevância; apenas correspondências em campos indexados afetam a pontuação.</p></li><li><p>Opções de consulta como fuzziness e outras ainda não são suportadas ao combinar uma expressão.</p></li><li><p>O texto em tempo de execução é analisado com o analisador padrão. Isso ainda não é configurável.</p></li></ul><p>Trabalhos estão em andamento para abordar essas limitações.</p><h2>Por que usar a busca em texto completo em vez de LIKE ou RLIKE no ES|QL?</h2><p>ES|QL já tinha duas formas de buscar strings sem índice: LIKE (padrões curinga) e RLIKE (expressões regulares). Ambos funcionam em qualquer expressão de string, então é justo perguntar o que o MATCH adiciona. A resposta é <a href="https://www.elastic.co/docs/manage-data/data-store/text-analysis">análise</a>, uma forma mais avançada de busca que utiliza técnicas como stemming e sinônimos. Também utiliza o tratamento de stopwords.</p><p>LIKE é simples correspondência de substrings, sem qualquer compreensão das palavras que compõem uma string. Digamos, por exemplo, que você esteja procurando mensagens de log sobre uma raposa:</p><p>Isso perde "Fox avistado perto do galinheiro" devido à capitalização, ao mesmo tempo em que iguala "Outfoxed pela competição", que não tem nada a ver com uma raposa. Ele falha em ambas as direções, com falsos negativos devido à capitalização e falsos positivos em substrings contidas em outras palavras.</p><p>Expressões regulares podem corrigir o problema do caso, mas o problema da fronteira de palavras fica feio rapidamente. Algo como:</p><p>E nem isso está certo ainda. Ele deixa de encontrar "fox" no final de uma frase seguida de ! ou ?, e não considera tabulações, aspas ou parênteses. Cada correção faz o padrão mais longo, e a próxima pessoa que ler a consulta precisa fazer engenharia reversa do que ele realmente está fazendo.</p><p>MATCH faz o problema desaparecer, pois executa tanto a consulta quanto o valor por um <a href="https://www.elastic.co/docs/reference/text-analysis/analyzer-reference">analisador</a>, que tokeniza texto em termos minúsculos e então faz a correspondência termo contra termo:</p><p>Essa consulta corresponderá a valores como "A rápida raposa marrom" e "FOX avistada perto do galinheiro", mas não a "Enganada pela concorrência" ou "protocolo FOXTROT ativado", independentemente de qualquer pontuação ao redor das palavras. Claro, tudo isso funciona para consultas de múltiplos termos, como MATCH(TO_TEXT(message), "brown fox"), exatamente do jeito que você esperaria.</p><p>Estão em andamento trabalhos para viabilizar o uso dos <a href="https://www.elastic.co/docs/reference/text-analysis/analysis-lang-analyzer">36 analisadores de linguagem dedicados</a>, com suporte para linguagens naturais em dados que nunca foram indexados ou mapeados.</p><h2>Casos de uso de busca de texto completo para dados não indexados e não mapeados</h2><p>Os exemplos acima pesquisaram valores calculados a partir de <a href="https://www.elastic.co/docs/manage-data/data-store/mapping">campos mapeados</a>. Os casos de uso mais interessantes do ES|QL MATCH em expressões envolvem dados que nunca foram pesquisáveis. Vamos examinar alguns.</p><h3>Como buscar campos não mapeados no ES|QL sem adicionar um mapeamento</h3><p>Às vezes, você deliberadamente deixa um campo fora dos seus mapeamentos, como um rastreamento de pilha verboso ou uma carga útil da requisição bruta. Você pode até mesmo omitir um blob para depuração. Indexar um desses consumiria espaço em disco e na heap em cada documento e não valeria a pena para um campo que você pode consultar uma vez por trimestre.</p><p>Essa decisão sempre foi final, porque <a href="https://www.elastic.co/search-labs/blog/esql-unmapped-fields">campos não mapeados</a> eram totalmente invisíveis para consultas. No Elasticsearch 9.5, você pode usar SET unmapped_fields="load" para fazer o ES|QL carregar campos não mapeados diretamente do documento de origem como palavras-chave. Em seguida, envolva isso em TO_TEXT, e agora você pode executar uma busca de texto completo:</p><p>Aqui, stack_trace nunca foi mapeado. Cada valor é obtido dos documentos originais e analisado em tempo real. Eles são combinados linha por linha. Isso dá trabalho de verdade e nunca será tão rápido quanto uma pesquisa <a href="https://www.elastic.co/docs/manage-data/data-store/index-basics">por índice invertido</a>. Mas agora, aquele campo que você não indexou pode ser pesquisado. Você pode manter o mapeamento pequeno para o caso do dia a dia e ainda responder à pergunta uma vez por trimestre quando importa.</p><h3>Busca de texto completo em um campo de palavra-chave sem reindexação</h3><p>Os campos de palavras-chave podem fazer muito. Eles oferecem correspondência exata, agregações rápidas e ordenação, por isso tantos campos acabam mapeados dessa forma. Mas os mapeamentos são decididos quando os dados chegam, e é fácil acabar em uma situação em que você queira fazer algo diferente do que pretendia originalmente com seus dados. Talvez product_name tenha sido mapeado como palavra-chave porque os dashboards fazem agregações com ele e, depois de receber um ano de dados de produto, alguém queira poder buscar valores dentro de product_name.</p><p>A resposta antiga era mudar o mapeamento para texto (ou adicionar um multicampo) e reindexar tudo. Isso pode ser demorado e caro, e em muitos casos, os usuários simplesmente não vão querer se preocupar com isso. A nova resposta é uma chamada de função:</p><p>TO_TEXT converte os valores das palavras-chave em texto em tempo real, então o MATCH os analisa em vez de compará-los exatamente. Isso permite consultar um campo de palavra-chave sem criar um mapeamento ou reindexar o documento de origem. Se a busca se tornar uma consulta diária, indexar o campo como texto ainda é a melhor opção a longo prazo, mas TO_TEXT lhe dá uma resposta hoje, sem nenhum esforço extra.</p><h3>Buscar no mesmo campo entre índices com mapeamentos diferentes</h3><p><a href="https://www.elastic.co/docs/reference/query-languages/esql/esql-multi-index">ES|QL pode abranger muitos índices</a>, e o mesmo campo não precisa ser sempre igual em todos eles. Quando o mesmo campo tem tipos diferentes em índices distintos, ES|QL o trata como um tipo de união, e uma função de conversão resolve o conflito. Vamos considerar um exemplo em que o campo mensagem é do tipo texto no modelo de índice deste ano, mas era uma palavra-chave no do ano passado:</p><p>Cada valor é analisado no momento da consulta, seja do índice de texto ou do índice de palavras-chave. Os valores das palavras-chave dos índices antigos são tokenizados e em minúsculas como todo o resto, então "connection reset" encontra "Connection RESET by peer", não importa em qual índice esteja.</p><p>Outro caso interessante é quando um campo é mapeado em apenas um índice, mas também presente (e não mapeado) no outro:</p><p>Há uma nuance que vale a pena destacar aqui. Se error_details estiver mapeado em logs-2026, mas não em logs-2025, o Elasticsearch não pode enviar essa consulta para <a href="https://lucene.apache.org/">Lucene</a>, porque os índices onde o campo não está mapeado retornariam silenciosamente nenhuma correspondência. Em vez disso, o planejador percebe que o campo pode não estar mapeado e avalia toda a MATCH linha por linha, de onde quer que as linhas tenham vindo. Você não precisa saber quais índices têm o campo mapeado; a consulta apenas responde à questão.</p><h2>Como ES|QL analisa texto no momento da consulta sem um índice invertido</h2><p>Quando o ES|QL planeja uma correspondência (match) contra uma expressão, ele analisa a string de consulta uma vez, no início, em um conjunto de termos. A forma como cada linha é então avaliada depende do tipo da expressão:</p><p><strong>Tipo de expressão</strong></p><p><strong>Processamento</strong></p><p><strong>Comportamento de correspondência</strong></p><p>texto (via TO_TEXT)</p><p>O analisador divide o valor em termos minúsculos</p><p>Comparação token-contra-token; uma linha corresponde se qualquer token for igual a qualquer termo de consulta (semântica OU)</p><p>palavra-chave, IP, data, numérico</p><p>Sem análise; constante de consulta convertida uma vez para o tipo nativo</p><p>Comparação exata por linha</p><p>Ambos os caminhos ignoram completamente o Lucene e avaliam os valores linha por linha. O caminho não textual reflete exatamente o que uma consulta match faz quando executada no Lucene para esses tipos de campo, de modo que a semântica permanece consistente independentemente de a sua consulta atingir ou não um índice.</p><p>Uma consulta de índice invertido faz seu trabalho no momento da ingestão e nunca acessa documentos que não correspondem no momento da consulta. Um match em tempo de execução faz essa análise no momento da consulta, para cada linha que a alcança. Uma é rápida porque o trabalho já aconteceu; a outra é flexível porque os dados não precisam ter sido indexados de forma alguma.</p><h2>O que vem a seguir para a busca de texto completo no ES|QL</h2><p>Tudo o que está neste post é a primeira parte de um esforço maior para fazer a busca no ES|QL funcionar em qualquer coisa, não apenas no que você indexou antes. As limitações mencionadas anteriormente estão sendo trabalhadas ativamente, e o roadmap vai além:</p><ul><li><p><strong>Pontuação.</strong> Correspondências em tempo de execução contribuem para _score, então você pode ordenar por relevância mesmo quando os dados nunca foram indexados.</p></li><li><p><strong>MATCH_PHRASE</strong><strong> em expressões.</strong> Já disponível no Elastic Cloud Serverless, e chegando ao Elastic Stack na versão 9.6.</p></li><li><p><strong>Analisadores configuráveis.</strong> Suporte a analisadores para MATCH e MATCH_PHRASE em expressões, permitindo analisadores de linguagem, derivação (stemming) e sinônimos no momento da consulta.</p></li><li><p><strong>Opções do MATCH.</strong> Opções como fuzziness e operador para correspondências em tempo real.</p></li><li><p><strong>Busca vetorial.</strong> Gerando vetores de incorporação por linha e executando k-nearest neighbors (kNN) em expressões dense_vector em tempo de execução, trazendo também a pesquisa semântica para dados não indexados.</p></li></ul><h2>Experimente hoje a busca de texto completo do ES|QL em expressões</h2><p>Você pode experimentar a busca em tempo de execução hoje mesmo. Já está disponível no Elastic Cloud Serverless, onde as novas capacidades do ES|QL são lançadas primeiro, e ele é disponibilizado como uma prévia técnica no Elasticsearch 9.5. Comece consultando a referência <a href="https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/search-functions">das funções de pesquisa</a> e verifique a página <a href="https://www.elastic.co/docs/reference/query-languages/esql/limitations">de limitações do ES|QL</a> para conhecer os limites atuais. É uma prévia técnica porque queremos seu feedback: se você buscar algo que nunca foi indexado e isso o surpreender, seja positiva ou negativamente, <a href="https://www.elastic.co/pt/community">gostaríamos muito de saber</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/full-text-search-unindexed-data</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/full-text-search-unindexed-data</guid>
    <category><![CDATA[ES|QL]]></category>
    <category><![CDATA[Mapeamentos]]></category>
    <dc:creator><![CDATA[Kevin Corcoran,Ioana Tagirta]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9a74e633d05585a8/6a730774b8c2e64c3ebe0fd4/image1.jpg" length="0" type="image/jpeg"/>
    <pubDate>Wed, 05 Aug 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Do prompt ao dashboard em menos de um minuto, 5 vezes mais barato: dashboards de IA e gráficos personalizados com Vega-Lite no Kibana]]></title>
    <description><![CDATA[Descreva suas métricas em linguagem natural e o chat com IA do Kibana gera dashboards e gráficos Vega-Lite baseados em ES|QL, desde gráficos de dispersão até formatação condicional e dicas de ferramenta personalizadas.]]></description>
    <content:encoded><![CDATA[<p>O<a href="https://www.elastic.co/docs/explore-analyze/ai-features/agent-builder/chat"> chat de IA</a> do Kibana agora cria dashboards completos<a href="https://www.elastic.co/docs/explore-analyze/visualize/esorql"> baseados em ES|QL</a> a partir de um comando em linguagem natural em menos de um minuto. No Elastic 9.5, isso passa para disponibilidade geral (GA) (<a href="https://www.elastic.co/pt/search-labs/blog/ai-dashboard-generation-elastic-agent-kibana">prévia técnica na versão 9.4</a>), com recuperação de erros que tenta novamente consultas com falha, custos de geração de ES|QL 5 vezes menores por meio do roteamento em camadas do modelo e controles interativos de filtro. Esta versão também adiciona a criação de gráficos<a href="https://www.elastic.co/docs/explore-analyze/visualize/custom-visualizations-with-vega"> Vega-Lite</a> por meio de linguagem natural, incluindo gráficos de dispersão, diagramas de caixa, formatação condicional e dicas de ferramenta personalizadas que normalmente você teria que codificar manualmente em JSON.</p><h2>Novidades na criação do dashboard de IA do Kibana</h2><p><strong>Capacidade</strong></p><p><strong>Prévia técnica (9.4)</strong></p><p><strong>GA (9,5)</strong></p><p>Tratamento de erros</p><p>Sem nova tentativa em consultas ES|QL</p><p>Tenta novamente automaticamente até três vezes, com inspeção e ajuste da consulta</p><p>Custo de geração ES|QL</p><p>Todas as consultas são roteadas pelo modelo primário</p><p>Roteamento em camadas de modelos, até 5 vezes mais barato</p><p>Intervalo de tempo</p><p>Janela padrão fixa</p><p>Seleção automática baseada na distribuição temporal dos dados</p><p>Controles de filtro</p><p>Sem suporte</p><p>Adicionado automaticamente para os campos mais relevantes</p><p>Gráficos Vega-Lite</p><p>Sem suporte</p><p>Criação em linguagem natural, incluindo diagramas de dispersão, diagramas de caixa, formatação condicional e dicas de ferramenta personalizadas</p><p>Edição de gráficos</p><p>Sem suporte</p><p>Editar painéis existentes do Vega-Lite usando linguagem natural</p><h3>Recuperação automática de erros para geração de dashboards por IA</h3><p>Na prévia técnica, o agente não tentou novamente as consultas ES|QL com falha. Na versão 9.5, ele detecta erros de consulta e tenta até três vezes, inspecionando cada erro e ajustando a consulta antes de desistir. Na prática, isso elimina a maioria dos problemas de painéis vazios e produz dashboards que renderizam corretamente na primeira tentativa.</p><h3>Por que a criação de dashboards de IA é mais barata no Elastic 9.5?</h3><p>Nem toda etapa na geração de dashboards exige o mesmo nível de raciocínio. Na 9.5, ES|QL passa por um modelo mais leve por padrão e retorna ao modelo primário apenas quando necessário. Se seu <a href="https://www.elastic.co/docs/explore-analyze/ai-features/agent-builder/connectors">conector</a> usa o Claude Opus 4.8 da Anthropic, isso significa que a geração de ES|QL em todos os painéis fica 5 vezes mais barata.</p><h3>Seleção automática do intervalo de tempo com base nos seus dados</h3><p>Dashboards só são úteis quando mostram o intervalo de dados correto. Agora, o agente aplica uma lógica aprimorada para escolher um intervalo de tempo que faça sentido para os dados que está consultando, a menos que o usuário solicite um intervalo de tempo específico. Ele considera a distribuição temporal dos dados e ajusta o intervalo de acordo, seja para a última hora em um incidente em andamento ou para os últimos 90 dias em uma análise de tendências, em vez de recorrer a uma janela fixa.</p><h3>Controles automáticos de filtro em dashboards gerados por IA</h3><p>A criação de dashboards agora oferece suporte a controles; ou seja, filtros interativos que permitem aos usuários filtrar um dashboard pelos valores dos campos sem editar as consultas subjacentes. Ao gerar um dashboard, o agente adiciona automaticamente controles na parte superior para os campos mais relevantes para filtragem.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4a5520e66ae76001/6a719a218a155220ed6498e7/image3.png" alt="Kibana AI chat generating an ES|QL-backed host metrics dashboard with automatic filter controls in 71 seconds" /><h2>Gráficos Vega-Lite a partir da linguagem natural: tipos de gráficos e formatação além dos padrões</h2><p><a href="https://vega.github.io/vega/">Vega</a> e <a href="https://vega.github.io/vega-lite/examples/">Vega-Lite</a> suportam uma ampla variedade de tipos de gráficos e personalizações no Kibana. Com a versão 9.5, você pode criá-los a partir de uma linguagem natural em vez de escrever o código você mesmo. </p><h3>Diagramas de dispersão, diagramas de caixa e mais tipos de gráficos Vega-Lite</h3><p>Diagramas de dispersão, gráficos de caixa, múltiplos pequenos facetados, gráficos de bolhas e gráficos de composição (como combinar histogramas com mapas de calor), entre muitos outros, são suportados pelo <a href="https://vega.github.io/vega-lite/examples/">Vega-Lite</a>. Um prompt como <em>Mostre-me um gráfico de dispersão entre tempo de resposta e tamanho da requisição, colorido pelo nome do serviço</em>, gera um painel Vega-Lite com os mapeamentos de dados corretos. Usam as paletas de cores padrão do Kibana para se misturar com o restante do dashboard.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf1651fe7ac903d47/6a719a49f124649f746fc1b4/image5.png" alt="Kibana dashboard with four Vega-Lite charts: box plot, bubble chart, faceted small multiples, and heatmap." /><h3>Formatação condicional, dicas de ferramentas personalizadas e rótulos em gráficos padrão</h3><p>Mesmo para tipos de gráficos que já são nativos de dashboards, como barra, linha ou área, às vezes você precisa de mais controle do que as capacidades padrão oferecem. O Vega-Lite via chat preenche essa lacuna. Alguns exemplos incluem:</p><ul><li><p><strong>Formatação condicional de cores:</strong> colorir pontos de dados acima de um limiar de forma diferente; por exemplo, tornar vermelhos os pontos de dados em uma linha ou barras quando algum indicador ultrapassa seu objetivo de nível de serviço (SLO). Peça ao agente algo como <em>pinte de vermelho qualquer ponto acima de 500ms no meu gráfico de linhas.</em> </p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc1211784e9033557/6a719a6ab966e1736163d7d1/image1.png" alt="Vega-Lite line and bar charts in Kibana with conditional colour formatting showing data points above a threshold in red" /><p></p></li><li><p><strong>Marcas e etiquetas personalizadas:</strong> adicione emojis, símbolos ou etiquetas de texto em linha aos pontos de dados para indicadores de status de fácil visualização.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte3c59c3748484bc1/6a719aa02888394fdc07bac1/image2.png" alt="Lite horizontal bar chart in Kibana with emoji flag labels and custom tooltip showing requests by country" /><p></p></li><li><p><strong>Dicas de ferramentas personalizadas:</strong> enriqueça as dicas exibidas ao passar o cursor com mais métricas, contexto ou valores calculados que não fazem parte dos eixos do gráfico. Peça algo como <em>Adicionar uma dica de ferramenta que mostre o total de registros e a % por barra.</em></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt43f241f4382b5b90/6a719ab7ded0cf3367f49275/image4.png" alt="Vega-Lite stacked bar chart in Kibana with custom tooltip showing total records and percentage of total by extension" /><p></p></li></ul><p>Isso também funciona para editar gráficos Vega existentes. Se você tem um painel Vega-Lite que precisa de ajustes, como alterar uma escala de cores, ajustar um eixo ou mudar o tipo de marca, descreva a mudança no bate-papo em vez de se aprofundar no código JSON.</p><h2>Como construímos a geração em linguagem natural do Vega-Lite no Kibana</h2><p>Gerar um gráfico Vega-Lite a partir de uma frase não consiste em fazer um único prompt <em>para o modelo gerar o JSON</em>. Construímos um pequeno pipeline autônomo que transforma a intenção em linguagem natural em um gráfico validado e respaldado por dados.</p><p>Quando um pedido chega, o agente primeiro determina se o Vega-Lite é a opção adequada. Para requisições Vega-Lite, a visualização se baseia em uma consulta ES|QL real no Elasticsearch e então usa um modelo para gerar o código Vega-Lite. Antes da renderização, o resultado passa por uma camada de normalização que corrige o esquema e vincula a consulta canônica. Também aplica transformações para segurança na renderização. </p><p>Algumas escolhas de design tornam esse fluxo de trabalho confiável:</p><ul><li><p><strong>Chamada tipada de ferramenta</strong>: a criação de gráficos é uma invocação de ferramenta estruturada, em vez de um código Vega-Lite de formato livre colado na conversa.</p></li><li><p><strong>Geração restrita</strong>: o modelo gera código Vega-Lite dentro de um esquema definido, tornando a saída mais previsível e fácil de validar.</p></li><li><p><strong>Exemplos selecionados:</strong> padrões estruturais, como facetas, marcas em camadas e mapas de calor, fornecem orientação sem copiar os dados subjacentes.</p></li><li><p><strong>Loops de execução e verificação</strong>: as consultas são executadas antes da criação do gráfico e as falhas de validação acionam novas tentativas corretivas para a geração de ES|QL.</p></li></ul><h2>Experimente a criação de dashboards por IA e gráficos Vega-Lite em Kibana</h2><p>Para experimentar a criação de dashboards em linguagem natural e os gráficos Vega-Lite, atualize para o <strong>Elastic 9.5</strong> (ou <a href="https://cloud.elastic.co/registration">inicie um teste gratuito</a>) e abra o <strong>chat</strong> no Kibana. Depois, peça para ele criar um dashboard a partir dos seus dados. Para Vega-Lite, tente pedir um tipo de gráfico que você sempre quis, mas nunca construiu, como um gráfico de dispersão ou um gráfico de bolhas. Se o resultado não estiver totalmente certo, diga ao agente o que mudar. Ele itera com você.</p><p>Isso requer uma licença empresarial. <a href="https://www.elastic.co/docs/explore-analyze/ai-features/agent-builder/chat#get-started">Comece agora mesmo</a>.</p><p><em>O lançamento e o cronograma de quaisquer recursos ou funcionalidades descritos neste artigo permanecem a exclusivo critério da Elastic. Os recursos ou funcionalidades não disponíveis no momento poderão não ser entregues no prazo previsto ou sequer serem disponibilizados.</em></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/ai-dashboards-kibana-vega-lite</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/ai-dashboards-kibana-vega-lite</guid>
    <category><![CDATA[Kibana]]></category>
    <category><![CDATA[ES|QL]]></category>
    <dc:creator><![CDATA[Marta Bondyra,Teresa Alvarez Soler]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt54406ad0378bc5fc/6a7199ffed03ccee0dac9d7c/image6.png" length="0" type="image/png"/>
    <pubDate>Tue, 04 Aug 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[LINQ para Elasticsearch ES|QL: escreva Consultas em C# e Consulte o Elasticsearch]]></title>
    <description><![CDATA[Explorando o novo provedor LINQ para Elasticsearch ES|QL no cliente Elasticsearch .NET, que permite escrever código C# automaticamente traduzido para consultas ES|QL.]]></description>
    <content:encoded><![CDATA[<p>A partir das <strong>versões 9.3.4</strong> e <strong>8.19.18</strong>, o cliente Elasticsearch .NET inclui um provedor de <a href="https://learn.microsoft.com/en-us/dotnet/csharp/linq/">Consulta Integrada em Linguagem (LINQ) </a>que traduz expressões LINQ em C# para a <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html">Linguagem de Consulta Elasticsearch (ES|QL)</a> em tempo de execução. Em vez de escrever manualmente as strings ES|QL, você compõe consultas usando <code>Where</code>, <code>Select</code>, <code>OrderBy</code>, <code>GroupBy</code> e outros operadores padrão. O provedor cuida da tradução, parametrização e desserialização dos resultados, inclusive o streaming por linha que mantém o uso da memória constante, independentemente do tamanho do conjunto de resultados.</p><h2>Sua primeira consulta</h2><p>Comece definindo um objeto CLR simples (POCO) que mapeia para o seu índice Elasticsearch. Os nomes das propriedades são resolvidos para nomes de coluna ES|QL via atributos <code>System.Text.Json</code> padrão, como <code>[JsonPropertyName]</code>, ou via <code>JsonNamingPolicy</code> configurado. As mesmas regras <a href="https://www.elastic.co/docs/reference/elasticsearch/clients/dotnet/source-serialization">de serialização de origem</a> que se aplicam ao restante do cliente também se aplicam aqui.</p>using System.Text.Json.Serialization;

public class Product
{
    [JsonPropertyName("product_id")]
    public string Id { get; set; }

    public string Name { get; set; }

    public string Brand { get; set; }

    [JsonPropertyName("price_usd")]
    public double Price { get; set; }

    [JsonPropertyName("in_stock")]
    public bool InStock { get; set; }
}<p>Com o tipo definido, uma consulta fica assim:</p>var minPrice = 100.0;
var brand = "TechCorp";

await foreach (var product in client.Esql.QueryAsync&lt;Product&gt;(q =&gt; q
    .From("products")
    .Where(p =&gt; p.InStock &amp;&amp; p.Price &gt;= minPrice &amp;&amp; p.Brand == brand)
    .OrderByDescending(p =&gt; p.Price)
    .Take(10)))
{
    Console.WriteLine($"{product.Name}: ${product.Price}");
}<p>O provedor traduz isso para o seguinte ES|QL:</p><p>Há alguns detalhes a serem observados:</p><ul><li><p><strong>Resolução do nome da propriedade:</strong> <code>p.Price</code> se torna <code>price_usd</code> por causa do atributo <code>[JsonPropertyName]</code>, e <code>p.Brand</code> se torna <code>brand</code> seguindo a política de nomenclatura padrão camelCase.</p></li><li><p><strong>Captura de parâmetros:</strong> As variáveis C# <code>minPrice</code> e <code>brand</code> são capturadas como parâmetros nomeados (<code>?minPrice</code>, <code>?brand</code>). Eles são enviados separadamente da string de consulta na carga JSON, o que evita injeções e permite o armazenamento em cache do plano de consulta no lado do servidor.</p></li><li><p><strong>Streaming:</strong> <code>QueryAsync&lt;T&gt;</code> retorna <code>IAsyncEnumerable&lt;T&gt;</code>. As linhas são materializadas uma de cada vez à medida que chegam do Elasticsearch.</p></li></ul><p>Você também pode inspecionar a consulta gerada e seus parâmetros sem executá-la:</p>var query = client.Esql.CreateQuery&lt;Product&gt;()
    .Where(p =&gt; p.InStock &amp;&amp; p.Price &gt;= minPrice &amp;&amp; p.Brand == brand)
    .OrderByDescending(p =&gt; p.Price)
    .Take(10);

Console.WriteLine(query.ToEsqlString());
// FROM products | WHERE (in_stock == true AND price_usd &gt;= 100) | SORT price_usd DESC | LIMIT 10

Console.WriteLine(query.ToEsqlString(inlineParameters: false));
// FROM products | WHERE (in_stock == true AND price_usd &gt;= ?minPrice AND brand == ?brand) | SORT price_usd DESC | LIMIT 10

var parameters = query.GetParameters();
// { "minPrice": 100.0, "brand": "TechCorp" }<h2>Como funciona? Uma breve revisão sobre o LINQ</h2><p>O mecanismo que torna possíveis os provedores LINQ é a distinção entre <code>IEnumerable&lt;T&gt;</code> e <code>IQueryable&lt;T&gt;</code>.</p><p>Quando você chama <code>.Where(p =&gt; p.Price &gt; 100)</code> em um <code>IEnumerable&lt;T&gt;</code>, o lambda compila para um <code>Func&lt;Product, bool&gt;</code>, um delegado regular que o runtime executa em processo. Isto é LINQ-to-Objects.</p><p>Quando você chama o mesmo método em um <code>IQueryable&lt;T&gt;</code>, o compilador C# envolve o lambda em um <code>Expression&lt;Func&lt;Product, bool&gt;&gt;</code> em vez disso. Essa é uma estrutura de dados que representa a <em>estrutura</em> do código em vez de sua forma executável. A árvore de expressões pode ser inspecionada, analisada e traduzida para outra linguagem em tempo de execução.</p>// IEnumerable: the lambda is a compiled delegate
IEnumerable&lt;Product&gt; local = products.Where(p =&gt; p.Price &gt; 100);

// IQueryable: the lambda is an expression tree, a data structure
IQueryable&lt;Product&gt; remote = queryable.Where(p =&gt; p.Price &gt; 100);<p>A interface <code>IQueryProvider</code> é o ponto de extensão. Qualquer provedor pode implementar <code>CreateQuery&lt;T&gt;</code> e <code>Execute&lt;T&gt;</code> para traduzir essas árvores de expressão para um idioma de destino. O Entity Framework usa isso para emitir SQL. O provedor LINQ to ES|QL o usa para emitir ES|QL.</p><p>A árvore de expressões para a consulta acima fica assim:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt521838e8b9c36649/6a1705b1839dfa5f40dcfdfe/f864cd18a390831f8d28503a29b5835efb1842f7-1000x720.png" alt="Árvore de expressões para a consulta de exemplo." /><p><em>Árvore de expressões para a consulta de exemplo.</em></p><p>A árvore é aninhada do avesso: <code>Take</code> envolve <code>OrderByDescending</code>, que envolve <code>Where</code>, que envolve <code>From</code>, que envolve a raiz <code>EsqlQueryable&lt;Product&gt;</code> constante. O predicado <code>Where</code> é ele próprio uma subárvore de <code>BinaryExpression</code> nós para os operadores <code>&amp;&amp;</code>, <code>&gt;=</code> e <code>==</code>, com folhas <code>MemberExpression</code> para acessos a propriedades e capturas de fechamento para as variáveis <code>minPrice</code> e <code>brand</code>. Essa é a estrutura de dados que o provedor percorre para produzir o ES|QL final.</p><h2>Nos bastidores: O pipeline de tradução</h2><p>O caminho de uma expressão LINQ até os resultados da consulta segue um pipeline de seis estágios:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt930670a505dd61ea/6a1705b3b339d58a54769ecf/2a2c772b63d720f61fc9a28b2f85668fa2db8d38-1999x1036.png" alt="Visão geral do pipeline de tradução." /><p><em>Visão geral do pipeline de tradução.</em></p><h3>1. Captura da árvore de expressão</h3><p>Quando você encadeia <code>.Where()</code>, <code>.OrderBy()</code>, <code>.Take()</code> e outros operadores em um <code>IQueryable&lt;T&gt;</code>, a infraestrutura padrão do LINQ constrói uma árvore de expressões. <code>EsqlQueryable&lt;T&gt;</code> implementa <code>IQueryable&lt;T&gt;</code> e delega para <code>EsqlQueryProvider</code>.</p><h3>2. Tradução</h3><p>Quando a consulta é executada (enumerando, chamando <code>ToList()</code> ou usando <code>await foreach)</code>), o <code>EsqlExpressionVisitor</code> percorre a árvore de expressões de dentro para fora. Ele despacha cada chamada de método LINQ para um visitante especializado:</p><p>Visitante</p><p>Traduz</p><p>Para</p><p>WhereClauseVisitor</p><p>.Where(predicate)</p><p>Condição ONDE</p><p>SelectProjectionVisitor</p><p>.Select(selector)</p><p>EVAL + KEEP + RENOMEAR</p><p>GroupByVisitor</p><p>.GroupBy().Select()</p><p>ESTATÍSTICAS ... POR</p><p>OrderByVisitor</p><p>.OrderBy() / .ThenBy()</p><p>Campo SORT [ASC\|DESC]</p><p>EsqlFunctionTranslator</p><p>EsqlFunctions.*, Math.*, métodos de string</p><p>80+ funções ES|QL</p><p>Durante a tradução, as variáveis C# referenciadas em expressões são capturadas como parâmetros nomeados.</p><h3>3. Modelo de consulta</h3><p>Os visitantes não produzem diretamente as strings. Em vez disso, produzem <code>QueryCommand</code> objetos, uma representação intermediária imutável. Um <code>FromCommand</code>, um <code>WhereCommand</code>, um <code>SortCommand</code>, e um <code>LimitCommand</code>, cada um representando um comando de processamento ES|QL. Eles são coletados para um modelo <code>EsqlQuery</code>.</p><p></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt788c9936976f2f62/6a1705b50e2e4910da419ff0/2adc349b6cf655b96b7b3e826a134e8a17fe42fd-1999x1036.png" alt="Modelo de consulta e padrão de comando." /><p><em>Modelo de consulta e padrão de comando.</em></p><p>Esse modelo intermediário é desacoplado tanto da árvore de expressão quanto do formato de saída. Ele pode ser inspecionado, interceptado (via <code>IEsqlQueryInterceptor</code>) ou modificado antes da formatação.</p><h3>4. Formatação</h3><p><code>EsqlFormatter</code> visita cada <code>QueryCommand</code> em ordem e gera a string final do ES|QL. Cada comando se transforma em uma linha, separada pelo operador pipe (|), que o ES|QL utiliza para encadear comandos de processamento. Identificadores que contêm caracteres especiais são automaticamente escapados com backticks.</p><h3>5. Execução</h3><p>A string ES|QL formatada e os parâmetros capturados são enviados para o endpoint <code>/_query</code> do Elasticsearch no corpo da requisição, como JSON. A interface <code>IEsqlQueryExecutor</code> abstrai a camada de transporte, e é aí que a arquitetura de pacotes em camadas se aplica.</p><h3>6. Materialização</h3><p><code>EsqlResponseReader</code> transmite a resposta JSON sem armazenar todo o conjunto de resultados na memória. Uma árvore <code>ColumnLayout</code> , pré-computada uma vez por consulta, mapeia ES|QL nomes de colunas (como <code>address.street</code>, <code>address.city</code>) para propriedades aninhadas do POCO. Cada linha é montada em uma instância <code>T</code> e gerada uma de cada vez via <code>IEnumerable&lt;T&gt;</code> ou <code>IAsyncEnumerable&lt;T&gt;</code>.</p><h2>A arquitetura em camadas</h2><p>A funcionalidade LINQ para ES|QL é dividida em três pacotes:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt662bd0dd8861b6b6/6a1705b7a929cf7086ae08a2/41b8aae860ecdc2480edcb1c1d4cc9b03cfb78c9-1999x1036.png" alt="Arquitetura do pacote." /><p><em>Arquitetura de pacotes.</em>
<a href="https://www.nuget.org/packages/Elastic.Esql"><strong><code>Elastic.Esql</code></strong></a> é o motor de tradução puro. Ele não tem dependência HTTP e contém os visitantes de expressões, o modelo de consulta, o formatador e o leitor de resposta. Você pode usá-lo de forma independente para criar e inspecionar consultas ES|QL sem nenhuma conexão com o Elasticsearch. Isso é útil para testes, logging de consultas ou para criar a sua camada de execução.</p>// Translation-only: no Elasticsearch connection needed
var provider = new EsqlQueryProvider();
var query = new EsqlQueryable&lt;Product&gt;(provider)
    .From("products")
    .Where(p =&gt; p.InStock)
    .OrderByDescending(p =&gt; p.Price);

Console.WriteLine(query.ToEsqlString());
// FROM products | WHERE in_stock == true | SORT price_usd DESC<p><a href="https://www.nuget.org/packages/Elastic.Clients.Esql"><strong><code>Elastic.Clients.Esql</code></strong></a> é um cliente ES|QL leve e independente. Ele adiciona a execução HTTP além de <code>Elastic.Esql</code> via <code>Elastic.Transport</code>. Se sua aplicação só precisa do ES|QL e nenhuma das outras APIs do Elasticsearch, essa é a opção de dependência mínima.</p><p><a href="https://www.nuget.org/packages/Elastic.Clients.Elasticsearch"><strong><code>Elastic.Clients.Elasticsearch</code></strong></a> é o cliente completo do Elasticsearch .NET. Também se baseia em <code>Elastic.Esql</code> e expõe o provedor LINQ via espaço de nome <code>client.Esql</code>. Esse é o ponto de entrada recomendado para a maioria das aplicações.</p><p>Ambos os pacotes da camada de execução fornecem a própria implementação do <code>IEsqlQueryExecutor</code>, a interface estratégica que conecta tradução e transporte.</p><p>Todos os três pacotes são compatíveis com o Native AOT quando usados com um <code>JsonSerializerContext</code> gerado por fonte. Para as informações completas sobre o cliente, consulte a <a href="https://www.elastic.co/docs/reference/elasticsearch/clients/dotnet/source-serialization#native-aot">documentação do Native AOT</a>.</p><h2>Além do básico</h2><p>O exemplo acima abordou filtragem, classificação e paginação. O provedor aceita um conjunto mais amplo de operações.</p><h3>Agregações</h3><p><code>GroupBy</code>, combinado com funções agregadas em <code>Select</code>, traduz-se em ES|QL <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/stats-by"><code>STATS ... BY</code></a>:</p>var stats = client.Esql.Query&lt;Product, object&gt;(q =&gt; q
    .GroupBy(p =&gt; p.Brand)
    .Select(g =&gt; new
    {
        Brand = g.Key,
        Count = g.Count(),
        AvgPrice = g.Average(p =&gt; p.Price),
        MaxPrice = g.Max(p =&gt; p.Price)
    }));

// -&gt; FROM products | STATS COUNT(*), AVG(price_usd), MAX(price_usd) BY brand<h3>Projeções</h3><p><code>Select</code>, com tipos anônimos gera os comandos <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/eval"><code>EVAL</code></a>, <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/keep"><code>KEEP</code></a> e <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/rename"><code>RENAME</code></a>:</p>var query = client.Esql.CreateQuery&lt;Product&gt;()
    .Select(p =&gt; new { ProductName = p.Name, p.Price, p.InStock });

// -&gt; FROM products | KEEP name, price_usd, in_stock | RENAME name AS ProductName<h3>Biblioteca repleta de funções</h3><p>Mais de 80 funções ES|QL estão disponíveis via classe <code>EsqlFunctions</code>, cobrindo data/hora, string, matemática, IP, correspondência de padrões e pontuação. Métodos <code>Math.*</code> padrão e <code>string.*</code> também são traduzidos:</p>.Where(p =&gt; p.Name.Contains("Pro"))       // -&gt; WHERE name LIKE "*Pro*"
.Where(p =&gt; EsqlFunctions.CidrMatch(      // -&gt; WHERE CIDR_MATCH(ip, "10.0.0.0/8")
    p.IpAddress, "10.0.0.0/8"))<h3>PESQUISAR ENTRAR</h3><p>Consultas cruzadas de índice traduzem-se para ES|QL <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/lookup-join"><code>LOOKUP JOIN</code></a>:</p>var enriched = client.Esql.Query&lt;Product, object&gt;(q =&gt; q
    .LookupJoin&lt;Product, CategoryLookup, string, object&gt;(
        "category-lookup-index",
        product =&gt; product.Id,
        category =&gt; category.CategoryId,
        (product, category) =&gt; new { product.Name, category!.CategoryLabel }));<h3>Acesso direto ao ES|QL bruto</h3><p>Para recursos do ES|QL que ainda não são cobertos pelo provedor LINQ, você pode adicionar fragmentos brutos:</p>var results = client.Esql.Query&lt;Product&gt;(q =&gt; q
    .Where(p =&gt; p.InStock)
    .RawEsql("| EVAL discounted = price_usd * 0.9"));<h3>Consultas assíncronas do lado do servidor</h3><p>Para consultas de longa duração, envie-as para processamento em segundo plano no servidor:</p>await using var asyncQuery = await client.Esql.SubmitAsyncQueryAsync&lt;Product&gt;(
    q =&gt; q.Where(p =&gt; p.InStock),
    asyncQueryOptions: new EsqlAsyncQueryOptions
    {
        WaitForCompletionTimeout = TimeSpan.FromSeconds(5),
        KeepAlive = TimeSpan.FromMinutes(10)
    });

await asyncQuery.WaitForCompletionAsync();
await foreach (var product in asyncQuery.AsAsyncEnumerable())
    Console.WriteLine(product.Name);<p>Consultas assíncronas do lado do servidor são úteis principalmente em consultas analíticas de longa duração/processamento de grandes conjuntos de dados que podem exceder os tempos-limite típicos, ou em ambientes sensíveis a tempo-limite com balanceadores de carga, gateways de API ou proxies que impõem tempos-limite de HTTP rigorosos. Consultas assíncronas evitam quedas de conexão ao separar o envio da obtenção dos resultados.</p><h2>Para começar</h2><p>LINQ to ES|QL está disponível a partir de:</p><ul><li><p><strong>Elastic.Clients.Elasticsearch v9.3.4</strong> (9.x branch)</p></li><li><p><strong>Elastic.Clients.Elasticsearch v8.19.18</strong> (8.x branch)</p></li></ul><p>Instale do NuGet:</p><p><code>dotnet add package Elastic.Clients.Elasticsearch</code></p><p>Os pontos de entrada estão em <code>client.Esql</code>:</p><p>Método</p><p>Returns</p><p>Caso de uso</p><p>Query&lt;T&gt;(...)</p><p>IEnumerable&lt;T&gt;</p><p>Execução síncrona</p><p>QueryAsync&lt;T&gt;(...)</p><p>IAsyncEnumerable&lt;T&gt;</p><p>Streaming assíncrono</p><p>CreateQuery&lt;T&gt;()</p><p>IEsqlQueryable&lt;T&gt;</p><p>Composição avançada e inspeção</p><p>SubmitAsyncQueryAsync&lt;T&gt;(...)</p><p>EsqlAsyncQuery&lt;T&gt;</p><p>Consultas de longa duração no servidor</p><p><a href="https://www.elastic.co/docs/reference/elasticsearch/clients/dotnet/linq-to-esql">Para obter a referência completa de recursos, incluindo opções de consulta, acesso a vários campos, objetos aninhados e tratamento de campos de vários valores, consulte a documentação do LINQ to ES|QL.</a></p><h2>Conclusão</h2><p>Do LINQ para ES|QL traz toda a expressividade do C# LINQ para a linguagem de consulta ES|QL do Elasticsearch, para que você escreva consultas componíveis e com tipagem forte sem precisar criar manualmente as strings de consulta. Com captura automática de parâmetros, materialização em streaming e arquitetura de pacotes em camadas que se adapta de traduções independentes ao cliente completo do Elasticsearch, ele se integra naturalmente a aplicações .NET de qualquer tamanho. Instale o cliente mais recente, direcione suas expressões LINQ para um índice e deixe o provedor cuidar do resto.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/linq-esql-c-elasticsearch-net-client</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/linq-esql-c-elasticsearch-net-client</guid>
    <category><![CDATA[ES|QL]]></category>
    <category><![CDATA[Banco de dados vetorial]]></category>
    <dc:creator><![CDATA[Florian Bernd,Martijn Laarman]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdfa35fbcbbf4959f/6a1705b9dc55de19a4e00d07/e54132e915217063e9ed0ec45059c6cfc38e31dd-1280x720.png" length="0" type="image/png"/>
    <pubDate>Wed, 01 Apr 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Estatísticas ES|QL mais rápidas com tabelas hash no estilo Swiss Tables]]></title>
    <description><![CDATA[Como o hashing inspirado em Swiss Tables e o design compatível com SIMD entregam acelerações consistentes e mensuráveis na linguagem de consulta do Elasticsearch (ES|QL).]]></description>
    <content:encoded><![CDATA[<p>Recentemente, substituímos partes importantes da implementação de tabelas hash do Elasticsearch por um design no estilo de Swiss Tables e observamos tempos de construção e iteração de 2 a 3 vezes mais rápidos em cargas de trabalho uniformes e de alta cardinalidade. O resultado é menor latência, melhor taxa de transferência e desempenho mais previsível para a linguagem de consulta do Elasticsearch (ES|QL) em estatísticas e operações de análise.</p><h2>Por que isso é importante</h2><p>A maioria dos fluxos de trabalho analíticos típicos acaba se resumindo ao agrupamento de dados. Seja calculando a média de bytes por host, contando eventos por usuário ou agregando métricas entre dimensões, a operação principal é a mesma: mapear chaves para grupos e atualizar agregados em execução.</p><p>Em pequena escala, praticamente qualquer tabela hash razoável funciona bem. Em grande escala (centenas de milhões de documentos e milhões de grupos distintos), os detalhes começam a importar. Fatores de carregamento, estratégia de sondagem, layout da memória e comportamento do cache podem fazer a diferença entre um desempenho linear e uma série de falhas de cache.</p><p>O Elasticsearch oferece suporte a essas cargas de trabalho há anos, mas estamos sempre buscando oportunidades para modernizar os algoritmos principais. Assim, avaliamos uma abordagem mais recente inspirada nas Swiss Tables e a aplicamos à maneira como o ES|QL calcula as estatísticas.</p><h2>Afinal, o que são Swiss Tables?</h2><p>As Swiss Tables são uma família de tabelas de hash modernas popularizadas pelo SwissTable do Google e posteriormente adotadas na Abseil e em outras bibliotecas.</p><p>Tabelas hash tradicionais gastam muito tempo atrás de ponteiros ou carregando chaves apenas para descobrir que não correspondem. O principal recurso das Swiss Tables é a capacidade de rejeitar a maioria das sondagens usando uma pequena estrutura de matriz residente em cache, armazenada separadamente das chaves e valores, chamada de <em>bytes de controle</em>, para reduzir drasticamente o tráfego de memória.</p><p>Cada byte de controle representa um único slot e, em nosso caso, codifica duas coisas: se o slot está vazio e uma pequena impressão digital derivada do hash. Esses bytes de controle são dispostos de maneira contígua na memória, geralmente em grupos de 16, tornando-os ideais para processamento de <a href="https://en.wikipedia.org/wiki/Single_instruction,_multiple_data">instrução única e dados múltiplos</a> (SIMD).</p><p>Em vez de sondar um slot de cada vez, as Swiss Tables analisam um bloco inteiro de controle de bytes usando instruções vetoriais. Em uma única operação, a CPU compara a impressão digital da chave de entrada com 16 slots e retira as entradas vazias. Somente os poucos candidatos que sobrevivem a esse processo rápido precisam ser carregados e comparados às chaves reais.</p><p>Esse design troca uma pequena quantidade extra de metadados por uma melhor localidade de cache e muito menos carregamentos aleatórios. À medida que a tabela cresce e as cadeias de sondagem se alongam, essas propriedades tornam-se cada vez mais valiosas.</p><h2>SIMD no centro</h2><p>A verdadeira estrela do espetáculo é o SIMD.</p><p>Bytes de controle não são apenas compactos, eles também são explicitamente projetados para serem processados com instruções vetoriais. Uma única comparação SIMD pode verificar 16 impressões digitais de uma vez, transformando o que normalmente seria um loop em algumas operações amplas. Por exemplo:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1f710e87dd749ab3/6a170cc46234e052dadb1a49/bd418778f0c6144f8f5f18419f6220ac0c935c7a-903x407.png" alt="SIMD no centro do Elasticsearch" /><p>Na prática, isso significa:</p><ul><li><p>Menos ramificações.</p></li><li><p>Cadeias de sondagem mais curtas.</p></li><li><p>Menos carregamentos da memória de chave e valor.</p></li><li><p>Utilização muito melhor das unidades de execução da CPU.</p></li></ul><p>A maioria das pesquisas nunca passa da verificação do byte de controle. Quando isso acontece, o restante do trabalho é focado e previsível. Esse é exatamente o tipo de carga de trabalho que CPUs modernas fazem bem.</p><h2>SIMD nos bastidores</h2><p>Para os leitores que gostam de espiar os bastidores, aqui está o que acontece ao inserir uma nova chave na tabela. Usamos a Panama Vector API com vetores de 128 bits, operando assim em 16 bytes de controle em paralelo.</p><p>O trecho a seguir mostra o código gerado em um Intel Rocket Lake com AVX-512. Embora as instruções reflitam esse ambiente, o design não depende do AVX-512. As mesmas operações vetoriais de alto nível são emitidas em outras plataformas usando instruções equivalentes (por exemplo, AVX2, SSE ou NEON).</p>; Load 16 control bytes from the control block
vmovdqu xmm0, XMMWORD PTR [r9+r10*1+0x10]

; Broadcast the 7-bit fingerprint of the new key across the vector
vpbroadcastb xmm1, r11d

; Compare all 16 control bytes to the new fingerprint
vpcmpeqb k7, xmm0, xmm1
kmovq rbx, k7

; Check if any matches were found
test rbx, rbx
jne &lt;handle_match&gt;<p>Cada instrução tem um papel claro no processo de inserção:</p><ul><li><p><code>vmovdqu</code>: Carrega 16 bytes de controle consecutivos no registrador <code>xmm0</code> de 128 bits.</p></li><li><p><code>vpbroadcastb</code>: Replica a impressão digital de 7 bits da nova chave em todas as faixas do registrador <code>xmm1</code>.</p></li><li><p><code>vpcmpeqb</code>: Compara cada byte de controle com a impressão digital transmitida, produzindo uma máscara de possíveis correspondências.</p></li><li><p><code>kmovq</code> + <code>test</code>: Move a máscara para um registrador de uso geral e verifica rapidamente se existe uma correspondência.</p></li></ul><p>Finalmente, decidimos sondar grupos de 16 bytes de controle por vez, pois o benchmarking mostrou que a expansão para 32 ou 64 bytes com registros mais amplos não oferecia nenhum benefício mensurável de desempenho.</p><h2>Integração em ES|QL</h2><p>Adotar o hashing com a técnica de Swiss Tables no Elasticsearch não foi uma simples substituição. O ES|QL tem requisitos rigorosos em relação à contabilidade de memória, segurança e integração com o restante do motor de computação.</p><p>Integramos a nova tabela hash de maneira precisa com o gerenciamento de memória do Elasticsearch, incluindo o reciclador de páginas e a contabilização de mecanismos de interrupção, garantindo que as alocações permaneçam visíveis e limitadas. As agregações do Elasticsearch são armazenadas densamente e indexadas por uma ID de grupo, mantendo o layout da memória compacto e rápido para iterações, além de possibilitar certas otimizações de desempenho ao permitir acesso aleatório.</p><p>Para chaves de bytes de comprimento variável, armazenamos em cache o hash completo junto com a ID do grupo. Isso evita o recálculo de códigos hash caros durante a sondagem e melhora a localidade do cache ao manter os metadados relacionados próximos uns dos outros. Durante o rehashing, podemos confiar no hash e bytes de controle em cache sem inspecionar os próprios valores, mantendo os custos de redimensionamento baixos.</p><p>Uma simplificação importante em nossa implementação é que as entradas nunca são excluídas. Isso elimina a necessidade de <em>lápides</em> (marcadores para identificar slots ocupados anteriormente) e permite que os slots vazios permaneçam realmente vazios, o que melhora ainda mais o comportamento da sondagem e mantém a eficiência das varreduras dos bytes de controle.</p><p>O resultado é um design que se encaixa naturalmente no modelo de execução do Elasticsearch, preservando as características de desempenho que tornam as Swiss Tables interessantes.</p><h2>Qual é o desempenho?</h2><p>Em pequenas cardinalidades, as Swiss Tables apresentam desempenho aproximadamente equivalente à implementação existente. Isso é esperado: quando as tabelas são pequenas, os efeitos de cache dominam menos e há pouca sondagem para otimizar.</p><p>À medida que a cardinalidade aumenta, o cenário logo muda.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt09b13af2fe162f59/6a170cc66f7f04485c9148b8/24900afc47ab07b0e9933f6117b99d0f4613f794-962x599.png" alt="Estatísticas ES|QL com tabelas hash no estilo Swiss Tables" /><p>O heatmap acima mostra fatores de melhoria de tempo para diferentes tamanhos de chave (8, 32, 64 e 128 bytes) entre cardinalidades de 1.000 a 10.000.000 de grupos. À medida que a cardinalidade aumenta, o fator de melhoria aumenta constantemente, chegando a 2 a 3 vezes para distribuições uniformes.</p><p>Essa tendência é exatamente o que o design prevê. Uma maior cardinalidade leva a cadeias de sondagem mais longas em tabelas hash tradicionais, enquanto a sondagem com a técnica Swiss Tables continua resolvendo a maioria das pesquisas em blocos de bytes de controle compatíveis com SIMD.</p><h2>O comportamento do cache conta a história</h2><p>Para entender melhor as acelerações, executamos os mesmos <a href="https://github.com/elastic/elasticsearch/pull/139343/files#diff-d0e0cc91a7495bf36b2d44eacce95f5185d01879e5f6c38089ac7a89aad17da7"><code>benchmarks</code></a> JMH sob o Linux <code>perf</code> e capturamos cache e estatísticas do TLB.</p><p>Em comparação com a implementação original, a versão Swiss Tables realiza cerca de 60% menos referências de cache no geral. Os carregamentos de cache no último nível caem mais de 4 vezes, e as falhas de carregamento da LLC caem mais de 6 vezes. Como as falhas de LLC costumam se traduzir diretamente em acessos à memória principal, essa redução sozinha explica grande parte da melhoria de ponta a ponta.</p><p>Mais próximo da CPU, observamos menos falhas de cache de dados L1 e quase 6 vezes menos falhas de dados TLB, indicando uma localidade espacial mais precisa e padrões de acesso à memória mais previsíveis.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb987a5bd98c0d7eb/6a170cc8a929cf9655ae0a25/6e49b7609fba83e33692cb9834552b6ca7e42a83-998x499.png" alt="Comportamento do cache: estatísticas originais x ES|QL com tabelas hash no estilo Swiss Tables" /><p>Esse é o benefício prático dos bytes de controle compatíveis com SIMD. Em vez de carregar repetidamente chaves e valores de locais de memória dispersos, a maioria das sondagens é resolvida analisando uma estrutura compacta residente no cache. Menos memória acessada significa menos falhas, e menos falhas significam consultas mais rápidas.</p><h2>Conclusão</h2><p>Ao adotar um design de tabela hash com a técnica Swiss Tables e apostar fortemente na sondagem compatível com SIMD, alcançamos uma aceleração de 2 a 3 vezes para cargas de trabalho de estatísticas ES|QL de alta cardinalidade, além de um desempenho mais estável e previsível.</p><p>Este trabalho destaca como estruturas de dados modernas conscientes da CPU podem desbloquear ganhos substanciais, mesmo para problemas já conhecidos, como tabelas hash. Há mais espaço para explorar aqui, como especializações adicionais de tipos primitivos e uso em outros caminhos de alta cardinalidade, como joins, todos eles apenas parte do esforço mais amplo e contínuo para modernizar continuamente os internos do Elasticsearch.</p><p>Se você tiver interesse nos detalhes ou quiser acompanhar o trabalho, confira o rastreamento de progresso de <a href="https://github.com/elastic/elasticsearch/pull/139343">pull request</a> e <a href="https://github.com/elastic/elasticsearch/issues/138799">meta issue</a> no Github.</p><p>Boa sorte com o hashing!</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/esql-swiss-hash-stats</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/esql-swiss-hash-stats</guid>
    <category><![CDATA[ES|QL]]></category>
    <dc:creator><![CDATA[Chris Hegarty,Matthew Alp,Nik Everett]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf76dd688c5b737e6/6a170cc9839dfa7fc7dcff40/21036e031070f14faccb2b53b22723de2750c391-1280x720.png" length="0" type="image/png"/>
    <pubDate>Mon, 19 Jan 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Introdução do suporte ao Elasticsearch no Google MCP Toolbox for Databases]]></title>
    <description><![CDATA[Veja como o suporte ao Elasticsearch agora está disponível no Google MCP Toolbox for Databases e adote as ferramentas ES|QL para integrar seu índice com segurança a qualquer cliente MCP.]]></description>
    <content:encoded><![CDATA[<p>Neste artigo, vamos explicar como usar o Google MCP Toolbox com o <a href="https://github.com/elastic/elasticsearch">Elasticsearch</a> para construir uma ferramenta simples de extração de informações de um índice do Elasticsearch.</p><p>Recentemente, contribuímos para o projeto open source <a href="https://github.com/googleapis/genai-toolbox">Google MCP Toolbox for Databases</a>, adicionando suporte ao Elasticsearch como banco de dados.</p><p>Com esse novo recurso, agora você pode usar o Google MCP Toolbox para se conectar ao Elasticsearch e "conversar" diretamente com seus dados.</p><h2>Elasticsearch</h2><p>Precisamos ter uma instância do Elasticsearch em execução. Você pode ativar uma avaliação gratuita no <a href="https://www.elastic.co/cloud">Elastic Cloud</a> ou instalá-lo localmente usando o <a href="https://github.com/elastic/start-local">script start-local</a>:</p>curl -fsSL https://elastic.co/start-local | sh<p>Isso instalará o Elasticsearch e o Kibana no seu computador e gerará uma chave API para ser usada na configuração do Google MCP Toolbox.</p><p>A chave API será mostrada como saída do comando anterior e armazenada em um arquivo .env na pasta elastic-start-local.</p><h2>Instale o conjunto de dados de exemplo</h2><p>Após a instalação, você pode fazer login no Kibana usando o nome do usuário <em>elastic</em> e a senha gerada pelo script start-local (armazenada em um arquivo .env).</p><p>Você pode instalar o conjunto de dados de <strong>pedidos de comércio eletrônico </strong>disponível no Kibana. Inclui um único índice chamado <strong>kibana_sample_data_ecommerce</strong> contendo informações sobre 4.675 pedidos de um website de comércio eletrônico. Para cada pedido, temos as seguintes informações:</p><ul><li><p>Informações do cliente (nome, ID, data de nascimento, e-mail, etc.)</p></li><li><p>Data do pedido</p></li><li><p>ID do pedido</p></li><li><p>Produtos (lista de todos os produtos com preço, quantidade, ID, categoria, desconto, etc.)</p></li><li><p>SKU</p></li><li><p>Preço total (sem impostos, com impostos)</p></li><li><p>Quantidade total</p></li><li><p>Informações geográficas (cidade, país, continente, localização, região)</p></li></ul><p>Para instalar os dados de exemplo, abra a página <strong>Integrações</strong> no Kibana (busque por “Integração” na barra de busca superior) e instale os “Dados de Exemplo”. Confira os detalhes na documentação aqui: <a href="https://www.elastic.co/docs/explore-analyze/#gs-get-data-into-kibana">https://www.elastic.co/docs/explore-analyze/#gs-get-data-into-kibana</a>.</p><p>O objetivo deste artigo é mostrar como é fácil configurar o Google MCP Toolbox para se conectar ao Elasticsearch e interagir com o <strong>índice kibana_sample_data_ecommerce</strong> usando linguagem natural.</p><h2>Google MCP Toolbox</h2><p>O Google MCP Toolbox é um servidor MCP open source projetado para facilitar a interação de aplicações e agentes de IA com bancos de dados de forma segura e eficiente. Antes chamado de "GenAI Toolbox for Databases", o projeto foi renomeado após adotar total compatibilidade com o <a href="https://www.anthropic.com/news/model-context-protocol">Protocolo de Contexto de Modelo</a> (MCP). Seu objetivo é eliminar o trabalho pesado tradicionalmente exigido ao conectar agentes a bancos de dados, lidando com agrupamento de conexões, autenticação, observabilidade e outras preocupações operacionais nos bastidores.</p><p>Essencialmente, o Toolbox permite que desenvolvedores definam ferramentas reutilizáveis e de alto nível que encapsulam interações com bancos de dados. Essas ferramentas podem então ser invocadas por qualquer cliente que cumpra o MCP — como um agente de IA — sem exigir que o cliente implemente consultas SQL de baixo nível ou gerencie conexões de banco de dados. Essa abordagem reduz drasticamente a quantidade de código padrão necessário para construir agentes conscientes de banco de dados, tornando possível integrar operações avançadas de dados em apenas algumas linhas de lógica de aplicação. Uma vez definida uma ferramenta, ela pode ser compartilhada entre vários agentes, frameworks ou linguagens (Figura 1).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte90070297ee83546/6a16fa29964cea694b08b972/137cea290bb70ad5da21853f9a6358cef4cf7451-1248x1056.png" alt="" /><p>Uma grande vantagem de usar o Toolbox é o modelo de segurança integrado. Fluxos de autenticação, como OAuth2 e OIDC, são aceitos de forma nativa, permitindo que os desenvolvedores evitem manipular ou armazenar credenciais confidenciais de bancos de dados em agentes. A plataforma também fornece recursos de observabilidade, incluindo métricas e rastreamento, no OpenTelemetry, que é essencial para depuração, monitoramento e implantações de produção. No geral, o MCP Toolbox serve como uma interface unificada, segura e extensível para interagir com seus dados de qualquer sistema habilitado pelo MCP.</p><h2>Como instalar o MCP Toolbox</h2><p>Você pode instalar o servidor MCP Toolbox no Linux usando o seguinte comando:</p>export VERSION=0.21.0
curl -L -o toolbox https://storage.googleapis.com/genai-toolbox/v$VERSION/linux/amd64/toolbox
chmod +x toolbox<p>Para instalá-lo no macOS ou Windows, siga as instruções detalhadas <a href="https://googleapis.github.io/genai-toolbox/getting-started/introduction/#installing-the-server">aqui</a>.</p><h2>Configure o Toolbox para Elasticsearch</h2><p>Para configurar o MCP Toolbox para Elasticsearch, precisamos criar um arquivo <strong>tools.yaml</strong> , conforme segue:</p>sources:
  my-cluster:
    kind: elasticsearch
    addresses:
      - http://localhost:9200
    apikey: &lt;insert-here-api-key&gt;

tools:
  customer-orders:
    kind: elasticsearch-esql
    source: my-cluster
    description: Get the orders made by a customer identified by name.
    query: |
    	FROM kibana_sample_data_ecommerce | WHERE MATCH(customer_full_name, ?name, {"operator": "AND"})
    parameters:
      - name: name
        type: string
        description: The customer name.

toolsets:
  elasticsearch-tools:
    - customer-orders<p>Você precisa trocar o valor <strong>&lt;insert-here-api-key&gt;</strong> por uma chave API válida do Elasticsearch. Se você estiver rodando o Elasticsearch localmente usando o start-local, pode encontrar a chave API no arquivo .env gerado pelo start-local, sob a variável <strong>ES_LOCAL_API_KEY</strong> . Se você estiver usando o Elastic Cloud, poderá gerar uma chave de API seguindo o procedimento descrito <a href="https://www.elastic.co/docs/deploy-manage/api-keys/elastic-cloud-api-keys">aqui</a>.</p><p>As ferramentas anteriores contêm a seguinte consulta ES|QL para Elasticsearch:</p><p>Se você não conhece o ES|QL, é uma linguagem de consulta desenvolvida pela Elastic, semelhante ao SQL, que pode ser usada para buscar em um ou mais índices. Saiba mais sobre ES|QL na documentação oficial <a href="https://www.elastic.co/docs/reference/query-languages/esql">aqui</a>.</p><p>A consulta acima busca todos os pedidos armazenados no <strong>índice kibana_sample_data_ecommerce</strong> que contêm o nome do cliente especificado, usando o parâmetro <strong>?name</strong> (o ponto de interrogação indica um parâmetro).</p><p>O nome do cliente é definido na configuração YAML anterior usando a string de tipo e a descrição "O nome do cliente".</p><p>Essa ferramenta pode ser usada para responder a perguntas sobre os pedidos de um cliente - por exemplo: <em>Quantos pedidos o cliente Foo fez em outubro de 2025?</em></p><p>As descrições das ferramentas e seus parâmetros são essenciais para extrair as informações relevantes da solicitação em linguagem natural do usuário. Essa extração é realizada usando o recurso de <strong>chamada de função</strong> de um modelo de linguagem grande (LLM). Na prática, um LLM pode determinar qual função (ferramenta) precisa ser executada para obter as informações necessárias, juntamente com os parâmetros apropriados para essa função.</p><p>Para saber mais sobre chamadas de função, sugerimos o artigo <a href="https://www.elastic.co/search-labs/blog/function-calling-with-elastic">Chamadas de função do OpenAI com Elasticsearch</a>, de Ashish Tiwari.</p><h2>Execute o servidor Toolbox</h2><p>Você pode executar o MCP Toolbox usando o arquivo tools.yaml anterior com o seguinte comando:</p>./toolbox --tools-file tools.yaml --ui<p>O parâmetro<strong> –ui</strong> executa uma aplicação web em <a href="http://127.0.0.1:5000/ui">http://127.0.0.1:5000/ui</a> (Figura 2).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0fb3953fae603572/6a16fa2aa6c2b92763e794fb/3caf2339b632bafd5847af1ed8b33b518a25b8a2-1600x314.png" alt="" /><p>Você pode selecionar <strong>Ferramentas</strong> &gt; <strong>customer-orders</strong> e inserir o nome do cliente no campo <strong>Nome</strong> do parâmetro (por exemplo, Gwen Sanders) e clicar no botão <strong>Executar</strong>. Você deve ver uma resposta JSON conforme a Figura 3.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltca02df8c78cb39ff/6a16fa2c961e6909b5c4cd22/b167e0142afb8919d9cedf6d0fa431d33d0e55f8-1600x933.png" alt="" /><p>A configuração está concluída, e o MCP Toolbox pode executar a ferramenta <strong>customer-orders</strong> para se comunicar com o Elasticsearch, rodando o ES|QL.</p><h2>Usando o MCP Toolbox com Gemini CLI</h2><p>Podemos usar qualquer cliente MCP para nos comunicar com o MCP Toolbox for Databases. Por exemplo, podemos usar o <a href="https://github.com/google-gemini/gemini-cli">Gemini CLI</a>, uma ferramenta de linha de comando, para usar o Gemini. Você pode instalar o Gemini CLI seguindo as instruções descritas <a href="https://geminicli.com/docs/get-started/installation/">aqui</a>.</p><p>Gemini CLI oferece uma extensão pré-configurada para MCP Toolbox, disponível em <a href="https://github.com/gemini-cli-extensions/mcp-toolbox">gemini-cli-extensions/mcp-toolbox</a>. Você pode instalar esta extensão executando o seguinte comando:</p>gemini extensions install https://github.com/gemini-cli-extensions/mcp-toolbox<p>Após a instalação, você precisa ir para o diretório em que armazenou o arquivo de configuração tools.yaml do MCP Toolbox e executar a CLI do Gemini da seguinte forma (essa etapa é necessária para que a CLI do Gemini seja configurada automaticamente com o MCP Toolbox):</p>gemini<p>Você deve ver uma saída conforme a Figura 4.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf7245c10b9e32cd6/6a16fa2d964cea073208b976/0f22df6d3da13c1dc50dcb560414fa7c630eb9a7-1434x341.png" alt="" /><p>Você pode verificar se a MCP Toolbox está conectada usando o seguinte comando:</p>/mcp list<p>Você deve ver a <strong>mcp_toolbox</strong> com as ferramentas<strong> de pedidos de clientes</strong> listadas (Figura 5).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte857b42dbe604203/6a16fa2f8b73cb531b189e33/97edbc40de9e44f469f6f3a09427532be167de0e-493x155.png" alt="" /><p>Se o MCP Toolbox estiver conectado à interface de comando Gemini, agora podemos tentar fazer algumas perguntas, como: "<em>Me dê os pedidos da cliente Gwen Sanders</em>." A CLI Gemini então solicitará permissão para executar a ferramenta de pedidos do cliente ao servidor mcp_toolbox (veja a Figura 6).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfb7ea752c1a39da7/6a16fa30cdacbfdf937d27ff/c052f3b5e49436903b804280c0065f67ee02444b-1432x284.png" alt="" /><p>Após a confirmação, a CLI Gemini executará a solicitação para a MCP Toolbox, recebendo uma resposta JSON como resultado e usando para formatar a resposta (Figura 7).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb9f6e04987137a9f/6a16fa320811ae2297e9fef7/7ea5128f1705951c2757af6da4b456d394d4a080-1432x734.png" alt="" /><p>A resposta da Gemini CLI emitirá um relatório indicando que Gewn Sanders fez apenas um pedido de 2 produtos, totalizando 132 euros.</p><h2>SDKs do MCP Toolbox</h2><p>O Google MCP Toolbox também oferece um SDK para acessar todas as funcionalidades de um programa escrito em Go, Python e Javascript.</p><p>Por exemplo, o Python SDK está disponível no Github na seguinte página: <a href="https://github.com/googleapis/mcp-toolbox-sdk-python">https://github.com/googleapis/mcp-toolbox-sdk-python.</a></p><p>Precisamos criar um agente simples para conectar à MCP Toolbox. Precisamos instalar os seguintes pacotes:</p>pip install toolbox-core
pip install google-adk<p>E crie um novo projeto de agente usando o comando a seguir:</p>adk create my_agent<p>Isso criará um novo diretório chamado <strong>my_agent</strong> com um <strong>arquivo agent.py</strong>.</p><p>Atualize <strong>my_agent/agent.py</strong> com o seguinte conteúdo para conectar ao Toolbox:</p>from google.adk import Agent
from google.adk.apps import App
from toolbox_core import ToolboxSyncClient

client = ToolboxSyncClient("http://127.0.0.1:5000")

root_agent = Agent(
    name='root_agent',
    model='gemini-2.5-flash',
    instruction="You are a helpful AI assistant designed to search information about a dataset of ecommerce orders.",
    tools=client.load_toolset(),
)

app = App(root_agent=root_agent, name="my_agent")<p>Crie um arquivo <strong>.env</strong> com sua chave API do Google:</p>echo 'GOOGLE_API_KEY="YOUR_API_KEY"' &gt; my_agent/.env<p>Por fim, podemos executar o agente e observar os resultados. Para executar o agente, você pode executar o seguinte comando:</p>adk run my_agent<p>Ou pode servi-lo por meio de uma interface web:</p>adk web --port 8000<p>Em ambos os casos, você pode interagir com a MCP Toolbox usando uma interface de perguntas e respostas. Por exemplo, você pode fazer a pergunta anterior: <em>Me dê os pedidos da cliente Gwen Sanders</em>.</p><p>Para saber mais sobre os diferentes SDKs, consulte <a href="https://googleapis.github.io/genai-toolbox/sdks/">esta página de documentação</a>.</p><h2>Conclusão</h2><p>Neste artigo, demonstramos a integração com o Elasticsearch para o Google MCP Toolbox for Databases. Usando um arquivo de configuração YAML simples, podemos definir um conjunto de ferramentas que traduzem perguntas de linguagem natural em consultas do Elasticsearch usando a linguagem ES|QL.</p><p>Mostramos como interagir com os conjuntos de dados kibana_sample_data_ecommerce, que contém pedidos de um website de e-commerce. Com esse arquivo de configuração, basta executar o servidor MCP Toolbox e conectar a ele a partir de qualquer cliente MCP.</p><p>Por fim, demonstramos como usar o Gemini CLI como cliente para conectar-se ao MCP Toolbox for Databases e consultar os dados de comércio eletrônico armazenados no Elasticsearch. Executamos uma consulta em linguagem natural para obter informações sobre pedidos de um cliente específico identificado pelo nome.</p><p>À medida que o ecossistema MCP continua crescendo, esse padrão — definições leves de ferramentas apoiadas por uma infraestrutura segura e pronta para produção — gera novas oportunidades para criar agentes cada vez mais capazes e com reconhecimento de dados com o mínimo esforço. Seja experimentando localmente com os conjuntos de dados de amostra da Elastic ou integrando capacidades de buscar em uma aplicação maior, o MCP Toolbox tem uma base confiável e extensível para interagir com os dados do Elasticsearch usando linguagem natural.</p><p>Para saber mais sobre o desenvolvimento de aplicações de IA agêntica, leia o artigo <a href="https://search-labs-redesign.vercel.app/search-labs/blog/ai-agentic-workflows-elastic-ai-agent-builder">Criando fluxos de trabalho de IA agêntica com Elasticsearch</a>, de Anish Mathur e Dana Juratoni.</p><p>Para saber mais informações sobre o Google MCP Toolbox, visite <a href="https://googleapis.github.io/genai-toolbox/getting-started/introduction/">https://googleapis.github.io/genai-toolbox/getting-started/introduction/</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/google-mcp-toolbox-elasticsearch-support</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/google-mcp-toolbox-elasticsearch-support</guid>
    <category><![CDATA[ES|QL]]></category>
    <category><![CDATA[IA agêntica]]></category>
    <dc:creator><![CDATA[Enrico Zimuel,Laurent Saint-Félix]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt72d49893c51407cf/6a16fa33cf4f2502bab2cf7e/425a48691f436ed47c9bdfaf5d561ac122b2c472-1062x668.png" length="0" type="image/png"/>
    <pubDate>Fri, 12 Dec 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[ES|QL na 9.2: Smart Lookup Joins e compatibilidade com séries temporais]]></title>
    <description><![CDATA[Explore três atualizações separadas do ES|QL no Elasticsearch 9.2: um LOOKUP JOIN aprimorado para uma correlação de dados mais expressiva, o novo comando TS para análise de séries temporais e o comando INLINE STATS flexível para agregação.]]></description>
    <content:encoded><![CDATA[<p>Elasticsearch 9.2, lançado em outubro, está repleto de avanços significativos que tornam a análise dos seus dados mais rápida, mais flexível e mais acessível do que nunca. No centro desta versão estão importantes melhorias no ES|QL, nossa linguagem de consulta baseada em pipes, projetada para oferecer ainda mais valor diretamente aos usuários finais.</p><p>Aqui está uma visão dos recursos do Elasticsearch 9.2 que transformarão seus fluxos de trabalho de análise de dados com o ES|QL.</p><h2>Revolucionando a correlação de dados: um Lookup Join mais inteligente, rápido e flexível</h2><p>O comando <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/lookup-join">LOOKUP JOIN</a> no ES|QL passou por uma transformação significativa no Elasticsearch 9.2, tornando-se dramaticamente mais eficiente e versátil. O comando LOOKUP JOIN combina dados da sua tabela de resultados da consulta ES|QL com registros correspondentes de um índice de modo de consulta especificado. Ele adiciona campos do índice de pesquisa como novas colunas à sua tabela de resultados com base em valores correspondentes no campo de join. Anteriormente, a junção de dados estava limitada a um único campo e igualdade simples. Não mais! Essas melhorias capacitam você a lidar com cenários complexos de correlação de dados de forma fácil.</p><p><strong>Os principais aprimoramentos do Lookup Join incluem:</strong></p><ul><li><p><strong>Joins de múltiplos campos:</strong> crie joins facilmente em múltiplos campos. Por exemplo, para unir <code>application_logs</code> com <code>service_registry</code> em <code>service_name</code>, <code>environment</code> e <code>version:</code></p></li></ul>FROM application_logs
| LOOKUP JOIN service_registry ON service_name, environment, version<ul><li><p><strong>Liberando predicados de joins complexos com expressões (prévia técnica):</strong></p></li></ul><p>Você não está mais limitado à simples igualdade. O LOOKUP JOIN agora permite especificar <strong>múltiplos critérios</strong> para correlação e incorporar uma variedade de <strong>operadores binários,</strong> incluindo ==, !=, &lt;, &gt;, &lt;=, e &gt;=. Isso significa que você pode criar condições de join altamente nuançadas, permitindo que você faça perguntas muito mais sofisticadas sobre seus dados.</p><p>Exemplo 1: encontrando métricas de aplicação com limite de SLA por serviço</p>FROM application_metrics
| LOOKUP JOIN sla_thresholds
      ON service_name == sla_service AND response_time &gt; sla_response_time<p>Exemplo 2: esta consulta calcula o valor devido com base em políticas regionais de precificação que mudam ao longo do tempo. Ele une três conjuntos de dados baseados em condições complexas de intervalo de datas e igualdade para calcular um <code>due_amount</code> final. A segunda busca usa o campo <code>measurement_date</code> do índice <code>meter_readings</code> e o campo <code>region_id</code> do índice <code>customers</code> para se juntar ao índice <code>pricing_policies</code> e encontrar a política de precificação correta para o <code>region</code> e <code>measurement_date</code> específicos.</p>FROM meter_readings
| LOOKUP JOIN customers
      ON meter_id
| LOOKUP JOIN pricing_policies
      ON
        region_id == region AND
          measurement_date &gt;= policy_begin_date AND
          measurement_date &lt; policy_end_date
| EVAL due_amount = (kwh_consumed * rate_per_kwh + base_charge) * (1 + tax_rate)
| EVAL period = policy_name
| KEEP customer_name, period, due_amount, measurement_date, kwh_consumed,
    rate_per_kwh, base_charge, tax_rate
| SORT measurement_date<ul><li><p><strong>Ganhos massivos de desempenho para joins filtrados: </strong></p></li></ul><p>Melhoramos o desempenho para "joins expansivos" que são filtrados usando condições de tabela de consulta. Os joins expansivos produzem múltiplas correspondências por linha de entrada, o que pode criar grandes conjuntos intermediários de resultados. Isso piora quando muitas dessas linhas são descartadas por um filtro subsequente. Na versão 9.2, otimizamos esses joins filtrando linhas desnecessárias quando um filtro é aplicado aos dados de consulta, evitando processar linhas que seriam descartadas. Em alguns cenários, esses joins podem ser até <strong>1000 vezes mais rápidos</strong>!</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltce2c948a9a00a348/6a17f1a20b0bed8c08dd368b/002c014ee29b1aaf9ddeb8c554bb76efe3ed180c-1572x954.png" alt="Ganhos de desempenho em joins filtrados" /><p>Essa otimização é crucial ao lidar com joins em expansão, onde uma pesquisa pode inicialmente gerar muitas correspondências potenciais. Ao aplicar filtros de forma inteligente, apenas os dados relevantes são processados, reduzindo drasticamente o tempo de execução da consulta e permitindo a análise em tempo real em grandes conjuntos de dados. Isso significa que você obtém seus insights muito mais rapidamente, mesmo com operações de join muito grandes ou complexas.</p><p><strong>Compatibilidade do Lookup Join Cross-Cluster Search (CCS):</strong></p><p>Quando o Lookup Join foi lançado como GA nas versões 8.19 e 9.1, ele não era compatível com Pesquisa entre clusters (CCS). Para organizações que operam em vários clusters, o LOOKUP JOIN agora se integra perfeitamente ao CCS na versão 9.2. Basta colocar seu índice de pesquisa em todos os clusters remotos onde você deseja realizar um join, e o ES|QL aproveitará automaticamente esses índices de pesquisa remota para unir seus dados remotos. Isso simplifica a análise distribuída de dados e garante um enriquecimento consistente em toda a sua implantação do Elasticsearch.</p><p>Essas melhorias significam que você pode correlacionar conjuntos de dados diversos com precisão, rapidez e facilidade sem precedentes, revelando insights mais profundos e acionáveis sem soluções complexas ou etapas de pré-processamento.</p><h2>Enriqueça seus dados com facilidade: Kibana Discover UX para Lookup Indices</h2><p>O enriquecimento de dados deve ser simples, não um obstáculo. Introduzimos uma experiência fantástica de usuário no Discover do Kibana para criar e gerenciar índices de lookup.</p><p><strong>Fluxo de trabalho intuitivo:</strong> o preenchimento automático abrangente do Discover guiará você pelo processo, sugerindo índices de pesquisa e campos de união no editor ES|QL, tornando incrivelmente fácil conectar seus dados carregados aos índices existentes. Digite o nome de um índice de consulta que não exista e obtenha acesso direto ao editor de pesquisa com um clique para criar o índice. Digite o nome de um índice de consulta existente e sugeriremos uma opção para editá-lo:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt20a75bcfd25eb156/6a17f1a46864a4864db688a1/d36fd6ffd6bc0bf8d31067f6266445c68d15c71c-1400x184.png" alt="" /><p><strong>Gestão em linha (CRUD):</strong> mantenha seus conjuntos de dados de referência atualizados com capacidades de edição em linha (Criar, Ler, Atualizar, Excluir) diretamente no Discover.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6263c5dd8c2c9d7e/6a17f1a5af47b614dbcde095/a0e4aa66540b1f725c24ccb0519d978415073bb6-1453x842.png" alt="Exemplo de uma consulta LOOKUP" /><p><strong>Upload de arquivos sem esforço: </strong>Agora você pode carregar arquivos diretamente, como CSVs, no Discover e usá-los instantaneamente nos seus <code>LOOKUP JOIN</code>. Chega de alternar entre diferentes áreas do Kibana!</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltddfcc3580af0e5c6/6a17f1a73e9e45965aba1587/0f5dc2c712af4c4cada50292a7c8b836eb02aa67-1600x748.png" alt="Adicione facilmente dados a um índice de consulta e use-os em JOINs de busca." /><p>Seja no mapeamento de IDs de usuário a nomes, adicionando metadados empresariais ou unindo arquivos de referência estáticos, este recurso democratiza o enriquecimento de dados, colocando a capacidade de melhorar com os joins diretamente nas mãos de cada usuário – rápido, simples e tudo em um só lugar.</p><h2>Mantenha seu contexto: Apresentando INLINE STATS (prévia técnica)</h2><p>Agregar dados é fundamental, mas às vezes você precisa ver os agregados <em>junto com</em> os dados originais. Temos o prazer de apresentar <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/inlinestats-by">INLINE STATS</a> como um recurso <strong>de visualização técnica</strong>.</p><p>Ao contrário do comando <code>STATS</code>, que substitui seus campos de entrada pela saída agregada, <code>INLINE STATS</code> preserva todos os campos de entrada originais e simplesmente adiciona os novos campos agregados. Isso permite que você execute outras operações nos campos de entrada originais <em>após</em> a agregação, proporcionando um fluxo de trabalho de análise mais contínuo e flexível.</p><p>Por exemplo, para calcular a distância média de voo mantendo as linhas individuais de voo:</p>FROM kibana_sample_data_flights
 | KEEP Carrier, Dest, DistanceMiles
 | INLINE STATS avgDist = ROUND(AVG(DistanceMiles))
       BY Dest
 | WHERE DistanceMiles &gt; avgDist<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9e0c7209db8a67ad/6a17f1a9e8fbcee5233a1a53/6eea943035e0ab371270084c504a06bb89f8b82b-1496x290.png" alt="Filtrando os resultados de voo com distância maior que a média usando o avgDist " /><p>Nessa consulta, <code>avgDist</code> é adicionado a cada linha com a <code>Dest</code>(inação) correspondente pela qual agrupamos e, como ainda temos as colunas de informações do voo, podemos filtrar os resultados para os voos com uma distância maior que a média.</p><h2>Compatível com séries temporais no ES|QL (prévia técnica)</h2><p>O Elasticsearch utiliza <a href="https://www.elastic.co/docs/manage-data/data-store/data-streams/time-series-data-stream-tsds">fluxos de dados de séries temporais</a> para armazenar métricas. Estamos adicionando suporte para agregações de séries temporais no ES|QL, através do comando <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/ts"><code>TS</code></a> source. Isso está disponível no Elastic Cloud Serverless e na versão 9.2 básica como uma prévia técnica.</p><p>A análise de séries temporais é amplamente baseada em consultas de agregação que resumem os valores das métricas em buckets de tempo, divididos por uma ou mais dimensões de filtragem. A maioria das consultas de agregação depende do processamento em duas etapas, com (a) uma função de agregação interna resumindo valores por série temporal e (b) uma função de agregação externa, combinando os resultados de (a) em todas as séries temporais.</p><p>O comando <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/ts"><code>TS</code></a> source, combinado com <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/stats-by"><code>STATS</code></a>, fornece uma forma concisa, porém eficaz, de expressar tais consultas ao longo de séries temporais. Mais concretamente, considere o seguinte exemplo para calcular a taxa total de solicitações por host e por hora:</p>TS my_metrics
| WHERE @timestamp &gt; NOW() - 1 day
| STATS SUM(RATE(requests))
      BY host, TBUCKET(1h)<p>Nesse caso, a função de agregação de séries temporais <code>RATE</code> é avaliada primeiro por série temporal e hora. Os agregados parciais produzidos são então combinados usando <code>SUM</code> para calcular os valores agregados finais por hospedado e por hora.</p><p>Você pode conferir a lista de funções de agregação de séries temporais disponíveis <a href="https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/time-series-aggregation-functions">aqui</a>. A taxa de <a href="https://www.elastic.co/docs/manage-data/data-store/data-streams/time-series-data-stream-tsds#time-series-metric">contador</a> agora é compatível, provavelmente a função de agregação mais importante para processar contadores.</p><p>O comando <code>TS</code> source é projetado para ser combinado com <code>STATS</code>, com execução ajustada para ser compatível com agregações de séries temporais de forma eficiente. Por exemplo, os dados são ordenados antes de serem inseridos no <code>STATS</code>. Comandos de processamento que possam enriquecer ou alterar os dados de série temporal ou sua ordem, como <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/fork"><code>FORK</code></a> ou <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/inlinestats-by"><code>INLINE STATS</code></a>, atualmente não são permitidos entre <code>TS</code> e <code>STATS</code>. Essa limitação pode ser eliminada no futuro.</p><p>A saída tabular <code>STATS</code> pode ser processada ainda com qualquer comando aplicável. Por exemplo, a consulta a seguir calcula a razão entre a média <code>cpu_usage</code> por host e hora para o valor máximo por host:</p>TS my_metrics
| STATS avg_usage = AVG(AVG_OVER_TIME(cpu_usage))
      BY host, time_bucket = TBUCKET(1h)
| INLINE STATS max_avg_usage = MAX(avg_usage)
      BY host
| EVAL ratio = avg_usage / max_avg_usage
| KEEP host, time_bucket, ratio
| SORT host, time_bucket DESC<p>Os dados de série temporal são armazenados em nosso mecanismo de armazenamento colunar subjacente, que é alimentado pelos valores de documento do Lucene. O comando TS adiciona execução vetorizada de consultas através do mecanismo de computação ES|QL. O desempenho das consultas geralmente é melhorado em mais de uma ordem de magnitude, em comparação com consultas <a href="https://www.elastic.co/docs/reference/query-languages/querydsl">DSL</a> equivalentes, e está em pé de igualdade com sistemas estabelecidos e específicos para métricas. No futuro, forneceremos uma análise detalhada de arquitetura e desempenho, então fique ligado.</p><h2>Expandindo seu conjunto de ferramentas: novas funções ES|QL</h2><p>Para aprimorar ainda mais a utilidade e a versatilidade do ES|QL, adicionamos um conjunto de novas <a href="https://www.elastic.co/docs/reference/query-languages/esql/esql-functions-operators">funções</a>:</p><p><strong>Manipulação de string: </strong><a href="https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/string-functions#esql-contains">CONTAINS</a>, <a href="https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/mv-functions#esql-mv_contains">MV_CONTAINS</a>, <a href="https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/string-functions#esql-url_encode">URL_ENCODE</a>, <a href="https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/string-functions#esql-url_encode_component">URL_ENCODE_COMPONENT</a>, <a href="https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/string-functions#esql-url_decode">URL_DECODE</a> para processamento mais robusto de texto e URL.</p><p><strong>Séries temporais e geoespaciais:</strong> <a href="https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/grouping-functions#esql-tbucket">TBUCKET</a> para buckets flexíveis de tempo, TO_DENSE_VECTOR para operações vetoriais e um conjunto abrangente de <a href="https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/spatial-functions">funções geoespaciais</a> como <code>ST_GEOHASH</code>, <code>ST_GEOTILE</code>, <code>ST_GEOHEX</code>, <code>TO_GEOHASH</code>, <code>TO_GEOTILE</code>, <code>TO_GEOHEX</code> para análise avançada baseada em localização.</p><p><strong>Formatação de datas:</strong> <a href="https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/date-time-functions#esql-day_name">DAY_NAME</a>, <a href="https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/date-time-functions#esql-month_name">MONTH_NAME</a> para representações de data mais legíveis.</p><p>Essas funções oferecem um conjunto mais rico de ferramentas para manipular e analisar seus dados diretamente dentro do ES|QL.</p><h2>Sob o capô: mais desempenho e eficiência</h2><p>Além dos recursos destacados, o Elasticsearch 9.2 inclui diversas otimizações de desempenho em todo o ES|QL. Aceleramos <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/where#like-and-rlike">RLIKE (LIST</a>) com pushdown nos casos em que a função substitui várias consultas RLIKE semelhantes. Com <code>RLIKE</code> (LIST), podemos unir essas consultas em um único autômato e aplicar um autômato em vez de vários. Também temos carregamento mais rápido dos campos de palavras-chave com ordenação de índice e otimizações gerais de consultas – essas melhorias garantem que suas consultas ES|QL sejam executadas de forma mais eficiente do que nunca.</p><h2>Comece hoje mesmo!</h2><p>Elasticsearch 9.2 representa um salto significativo para o ES|QL, trazendo uma melhoria e flexibilidade sem precedentes para seus fluxos de trabalho de análise de dados. Incentivamos você a explorar esses novos recursos e experimentar a diferença que eles fazem.</p><p>Para uma lista abrangente de todas as mudanças e aprimoramentos no Elasticsearch 9.2, consulte as <a href="https://www.elastic.co/guide/en/elasticsearch/reference/9.2/release-notes-9.2.0.html">notas de lançamento oficiais</a>. Boas consultas!</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/esql-elasticsearch-9-2-multi-field-joins-ts-command</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/esql-elasticsearch-9-2-multi-field-joins-ts-command</guid>
    <category><![CDATA[ES|QL]]></category>
    <dc:creator><![CDATA[Tyler Perkins,Kostas Krikellas,Julian Kiryakov]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd30ea8cac3809cc3/6a17f1aa4b055dd8734322f8/415894e21e7758c907d6e60d4efc94230349beef-2012x1164.png" length="0" type="image/png"/>
    <pubDate>Tue, 02 Dec 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Experiência do editor ES|QL do Elasticsearch versus o analisador de eventos PPL do OpenSearch.]]></title>
    <description><![CDATA[Descubra como os recursos avançados do ES|QL Editor aceleram seu fluxo de trabalho, em contraste direto com a abordagem manual do PPL Event Analyzer da OpenSearch. 
]]></description>
    <content:encoded><![CDATA[<p>A <a href="https://www.elastic.co/blog/getting-started-elasticsearch-query-language">Linguagem de Consulta Elasticsearch</a> (ES|QL), disponível ao público em geral desde a versão 8.14, introduz uma linguagem e um mecanismo de consulta desenvolvidos especificamente para pesquisa, observabilidade e investigações de segurança. Ao contrário da Piped Processing Language (PPL) do OpenSearch, que se baseia fortemente em linguagens de processamento em pipeline já existentes, o ES|QL foi construído do zero com foco em refinamento, usabilidade e integração perfeita em toda a plataforma Kibana.</p><p>Neste blog, exploraremos a experiência do desenvolvedor com o Editor ES|QL no Elasticsearch 9.1, comparando-a com o PPL no Analisador de Eventos (PPL, na sigla em inglês) do OpenSearch 3.2.</p><p>As diferenças tornam-se rapidamente evidentes: o Editor ES|QL oferece preenchimento automático inteligente, ajuda contextual, consultas recomendadas e suporte a consultas entre clusters, capacitando não apenas usuários iniciantes, mas também usuários de nível especialista. O design cuidadoso para a criação de ES|QL também se reflete na inspeção integrada de consultas e na integração holística por meio de fluxos de trabalho do Kibana, por exemplo, com as Consultas Recentes.</p><p>Em contrapartida, o PPL carece de suporte comparável para autocompletar, orientação contextual e consultas distribuídas, criando uma curva de aprendizado mais acentuada e exigindo mais tentativas e erros.</p><h2>Tornando o ES|QL mais fácil de aprender e usar.</h2><p>Começar a usar uma nova linguagem de consulta pode muitas vezes parecer algo assustador. O editor ES|QL<strong>, </strong>integrado diretamente ao <strong>Kibana Discover</strong>, foi projetado para facilitar esse processo, oferecendo suporte não apenas à criação e depuração de consultas, mas também acelerando a sua familiarização e o seu domínio da linguagem. À medida que o editor ajuda a reduzir o atrito nas tarefas diárias, você pode mudar o foco da sintaxe e da tentativa e erro para a busca de soluções. Você pode ler mais sobre esses princípios e como os integramos ao editor <a href="https://www.elastic.co/search-labs/blog/improving-esql-editor-experience-in-kibana">aqui</a>.</p><p>Essa experiência de edição não se limita ao Discover; trata-se de um módulo de código reutilizável que estamos trabalhando para <strong>integrar a outras partes do Kibana</strong>, como Dashboards, alertas do Kibana e mapas do Kibana.</p><h3>Preenchimento automático inteligente: acelerando a criação de suas consultas.</h3><p>O recurso de autocompletar do ES|QL Editor é abrangente, oferecendo sugestões de funções, argumentos, literais e até mesmo funções aninhadas compatíveis, uma funcionalidade notavelmente ausente no PPL. Na verdade, foi reconstruído do zero, conforme descrito <a href="https://www.elastic.co/search-labs/blog/esql-autocomplete-rebuilt">aqui</a>.</p><p>A validação é executada enquanto o usuário digita, conforme descrito <a href="https://www.elastic.co/search-labs/blog/improving-esql-editor-experience-in-kibana">aqui</a>, e sugerirá campos, além de notificar o usuário sobre erros. Isso reduz a carga mental dos usuários e ajuda a prevenir erros logo no início do processo de criação de consultas.</p><p>Exemplo: Campos e funções compatíveis são sugeridos neste aninhamento:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdb186fc80dcc66f5/6a17f311e9ea8737a5a9c720/a4d7b2819c34fab31bced7873257b8932b623fba-1502x473.png" alt="Sugestão de aninhamento de campos e funções compatíveis." /><p>Algo que a PPL não suporta:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt250ae79e8f33b598/6a17f3127f6f150d3dc09c74/6f3a89b1255b8a3a762022a2704fdd1c2987e5f9-1013x335.png" alt="Uma função que o PPL não suporta." /><p>Mesmo com o recurso de autocompletar inteligente guiando você pelas funções, argumentos e funções aninhadas compatíveis, você ainda pode querer uma compreensão mais profunda das opções disponíveis. É exatamente aí que a ajuda contextual do ES|QL Editor se torna indispensável, oferecendo assistência imediata dentro do próprio editor para esclarecer e aprimorar o desenvolvimento de suas consultas.</p><h3>Ajuda contextual ao seu alcance</h3><p>Informações adicionais sobre um comando gerado pelo recurso de autocompletar podem ser acessadas com um clique Ctrl+Espaço. Um painel aparece imediatamente com detalhes sobre a função, o argumento ou o campo em questão. Essa interação simplificada mantém os desenvolvedores focados, fornecendo orientação imediata sem obrigá-los a sair do editor ou a procurar documentação externa. Isso reduz o tempo gasto em pesquisas de sintaxe e ajuda a evitar erros comuns antes que eles ocorram.</p><p>Veja como funciona na prática:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt407e42acc7f53f15/6a17f3134b055d128d43231a/2797f9b5e002dbd83c46475c4ed4dcdc86144a01-1343x522.gif" alt="Um comando gerado pelo recurso de autocompletar com Ctrl+Espaço para contexto adicional." /><p>O PPL não possui esse nível de orientação integrada, deixando os usuários dependentes de documentação externa ou do método de tentativa e erro. Essa ausência não é apenas uma característica faltante; ela evidencia uma disparidade mais ampla na filosofia de design. ES|QL prioriza uma experiência ponderada e contextualizada que se adapta aos dados e ao fluxo de trabalho do usuário. Essa diferença torna-se mais acentuada à medida que as consultas aumentam em complexidade, fazendo do ES|QL Editor um ambiente mais eficiente e confiável tanto para aprendizado quanto para uso em produção.</p><h3>Consultas recomendadas que levam em consideração o contexto dos dados.</h3><p>O Editor ES|QL fornece consultas recomendadas que são automaticamente adaptadas aos dados com os quais você está trabalhando, como registros. Em vez de apresentar um editor em branco, ele destaca os pontos de partida mais relevantes para casos de uso comuns. Selecionar uma Consulta Recomendada gera uma consulta canônica que pode ser usada imediatamente e refinada conforme necessário. Essa abordagem acelera o desenvolvimento de consultas, especialmente para novos usuários que ainda não conhecem toda a sintaxe.</p><p>Aqui está um exemplo em que um usuário seleciona a consulta “Detectar Ponto de Mudança”:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfc6c41f9e1e3cb40/6a17f3156864a43791b688d0/3284c9340d41298820fbf8c7702abad946b48248-925x370.gif" alt="O que acontece quando um usuário seleciona a consulta &quot;Detectar Ponto de Mudança&quot;?" /><p>Compare isso com a experiência do PPL:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6511bb51659feaf3/6a17f3166864a427c2b688d4/5c3e59dadc6210aede3366bdd081887bcbae7a54-969x798.png" alt="A experiência PPL, com apenas o recurso básico de preenchimento automático." /><p>Em contrapartida, o PPL oferece apenas o preenchimento automático básico, deixando você responsável por montar consultas sem contexto ou estrutura. Essa falta de orientação pode levar à frustração e à tentativa e erro.
Com as Consultas Recomendadas que levam em consideração os dados do Editor ES|QL, você pode evitar começar do zero ou memorizar a sintaxe para tarefas rotineiras. O editor reduz a carga cognitiva, ajuda a prevenir erros e permite que você se concentre na resolução de problemas e em objetivos mais amplos, como executar pesquisas entre clusters, em vez de se preocupar com a construção de consultas.</p><h2>Consultas intuitivas entre clusters</h2><p>O recurso de autocompletar do editor ES|QL continua sendo superior, mesmo ao trabalhar com vários clusters remotos <a href="https://elastic.aiops.work/search-labs/blog/esql-cross-cluster-search">com o CCS</a>. Eis o motivo:</p><h3>O editor ES|QL oferece preenchimento automático contínuo, mesmo em clusters diferentes.</h3><p>O recurso de autocompletar no editor ES|QL suporta não apenas nomes de clusters, mas também<strong> índices locais e remotos</strong>. Conforme explicado <a href="https://www.elastic.co/search-labs/blog/esql-cross-cluster-search">aqui</a>, isso funciona graças a uma arquitetura de nó coordenador, que ajuda a validar e gerar o plano de consulta a ser enviado aos nós locais, executar a consulta e agregar os resultados antes de enviá-los de volta ao usuário. Sem precisar digitar o nome completo do cluster remoto, digitar “:” inicia o processo de autocompletar para o índice remoto. E você não está limitado ao prefixo.</p><p>Isso facilita a descoberta e a consulta em conjuntos de dados distribuídos sem a necessidade de memorizar convenções de nomenclatura ou alternar entre contextos.</p><p>Aqui está um exemplo em que o usuário digita apenas “clu:g” para localizar um índice remoto:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4fadd61aa6d2a212/6a17f3186864a4a385b688d8/bae1fbacb2320e4d07f41291ea57c9bcf15bf8a5-1092x523.gif" alt="Um exemplo em que o usuário digita apenas “clu:g” para localizar um índice remoto." /><p>Em nítido contraste, a PPL fornece apenas preenchimento básico para índices locais, com sugestões restritas a correspondências de prefixos. Os clusters remotos devem ser digitados manualmente, o que aumenta a probabilidade de erros e torna a criação de consultas mais lenta.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3949402084cf303a/6a17f31a6864a482b1b688dc/e38793c0cc7c6cc7dc0fd4779a3e24ffbb6e0838-1094x263.gif" alt="Um exemplo de como o PPL fornece apenas preenchimento automático básico para índices locais, com sugestões restritas a correspondências de prefixos." /><p>O PPL fornece preenchimento automático apenas para índices locais e as sugestões são restritas ao prefixo:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcaa81c403f354e1f/6a17f31c6864a4e620b688e0/5310f824942f94485cace2558ea72c56a0971e22-862x197.png" alt="Outro exemplo de como o PPL fornece preenchimento automático apenas para índices locais e as sugestões são restritas ao prefixo." /><p>O ES|QL vai além, <a href="https://www.elastic.co/docs/solutions/search/cross-cluster-search#exclude-problematic-clusters">permitindo exclusões</a> diretamente usando um sinal negativo, oferecendo controle preciso sobre quais clusters participam da sua exploração. Essa funcionalidade é particularmente valiosa ao trabalhar com ambientes híbridos, onde pode ser necessário incluir ou omitir conjuntos de dados específicos durante investigações entre clusters.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf0ca78bfbceb60ae/6a17f31d6864a4199bb688e4/f23ca17f58fbf8e6d27419c028274cb91f30a549-937x78.png" alt="Um exemplo de codificação de uma investigação entre clusters." /><p>Essas melhorias refletem o foco mais amplo do Elasticsearch em reduzir o atrito na busca entre clusters. Ao facilitar a construção e o gerenciamento de consultas distribuídas, o ES|QL Editor permite que analistas e desenvolvedores se concentrem em insights em vez de sintaxe, enquanto o PPL deixa grande parte dessa responsabilidade para o usuário. Assim como o ES|QL Editor simplifica a criação de consultas entre clusters, ele também fornece ferramentas para inspecionar como essas consultas são executadas, garantindo transparência e monitoramento de desempenho em vários clusters.</p><h3>Utilizando a ferramenta Inspection para analisar detalhes da pesquisa entre clusters.</h3><p>A ferramenta Inspect, acessível a partir do Editor ES|QL, foi projetada para fornecer metadados com informações explícitas sobre a execução da consulta em todos os clusters. Essa funcionalidade está habilitada no Kibana Discover e pode ser acessada diretamente no inspetor de consultas, permitindo analisar o progresso e os detalhes da pesquisa, o que é particularmente crucial para <strong>a Pesquisa entre Clusters</strong> (<a href="https://www.elastic.co/docs/reference/query-languages/esql/esql-cross-clusters">CCS</a>). Essa funcionalidade ajuda você a monitorar o progresso da pesquisa e a entender o desempenho das consultas em conjuntos de dados distribuídos.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf79eaeedac3600b9/6a17f31fabe0f26f06dfeb4b/5d1c204f70171526fff924c30ea8ad08121a0f8d-919x523.gif" alt="A ferramenta de inspeção permite analisar detalhes de pesquisa entre clusters." /><p>Essa visibilidade detalhada da execução de consultas, especialmente para pesquisas distribuídas complexas, permite garantir o desempenho ideal e a resolução de problemas.</p><p>Além de compreender a mecânica das consultas individuais, o ES|QL Editor aprimora ainda mais a experiência do usuário, incorporando funcionalidades essenciais em toda a plataforma Kibana, promovendo um fluxo de trabalho contínuo e sem interrupções.</p><h2>Experiência de consulta unificada com ES|QL e Kibana</h2><p>Uma das fontes mais comuns de atrito na análise orientada por consultas é a troca de contexto. Muitas vezes você precisa relembrar perguntas que já escreveu. Cada interrupção quebra o foco e atrasa as investigações. O ES|QL Editor resolve isso integrando o histórico de consultas em todo o Kibana.</p><h3>Consultas recentes</h3><p>O recurso <a href="https://www.elastic.co/search-labs/blog/esql-piped-query-language-goes-ga">Consultas Recentes</a> no Editor ES|QL ajuda você a manter o fluxo de trabalho, tornando o trabalho anterior instantaneamente acessível. No editor ES|QL do Discover, você pode visualizar, executar novamente e marcar com estrela suas últimas 20 consultas, garantindo que as consultas mais usadas ou complexas estejam a apenas um clique de distância. Essas consultas salvas também são transferidas para o Kibana, integrando-se a painéis, visualizações, alertas e mapas, para que você não precise sair da tela atual nem digitar os comandos novamente. Isso reduz o trabalho repetitivo, acelera as investigações e minimiza o risco de erros.</p><p>Por exemplo, um usuário pode utilizar as Consultas Recentes no Editor ES|QL do Discover (e marcá-las com uma estrela):</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt49033a46a0805ec8/6a17f321e9ea87a505a9c724/eb0f9fe37b92dec421c394d31ae7d90afebe062e-1421x793.png" alt="Um exemplo de como usar as consultas recentes no editor ES|QL no Discover (e como marcá-las com uma estrela)." /><p>As consultas recentes estão integradas no painel de controle:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta2f7c745cdc5e5f1/6a17f323a2929932a1d02da9/b84cd3a9bdec58812360d2aba4fc7713363ee3cc-1411x797.png" alt=" Consultas recentes integradas em um painel de controle." /><p>O PPL não oferece nenhuma funcionalidade comparável, obrigando os usuários a recorrerem à cópia e colagem manual ou a anotações externas para reutilizar consultas. A diferença vai além da conveniência; ela reflete a estratégia da Elastic de construir o ES|QL como uma linguagem verdadeiramente integrada ao ecossistema Kibana. Com recursos como Consultas Recentes, o ES|QL Editor não apenas simplifica os fluxos de trabalho diários, mas também estabelece as bases para funcionalidades mais avançadas, agora em versão prévia técnica, garantindo que a experiência continue a evoluir.</p><h2>Conclusão</h2><p>ES|QL é mais do que uma sintaxe; reflete a estratégia da Elastic para melhorar a forma como os usuários pesquisam, exploram e analisam dados. Com autocompletar inteligente, consultas recomendadas sensíveis ao contexto, orientações integradas ao editor e ferramentas como o Inspect, o ES|QL Editor acelera o aprendizado, reduz erros e simplifica fluxos de trabalho complexos, como a análise entre clusters. Integrado ao Kibana, ele conecta consultas perfeitamente a painéis, alertas e visualizações, garantindo um fluxo de trabalho ininterrupto.</p><p>Em resumo, ES|QL não é apenas mais uma linguagem de encaminhamento; é um mecanismo de consulta cuidadosamente projetado, aliado a uma interface de usuário intuitiva, que redefine fundamentalmente a forma como você interage com seus dados, oferecendo uma experiência integrada, inteligente e em constante evolução, que contrasta fortemente com a natureza frequentemente sequencial e menos guiada do OpenSearch PPL.</p><h2>O que vem a seguir?</h2><p>Este blog apenas aborda superficialmente o ES|QL. As próximas publicações aprofundarão as comparações com o OpenSearch PPL e explorarão recursos geoespaciais, de visualização e funcionalidades futuras do editor, como <a href="https://www.elastic.co/docs/explore-analyze/dashboards/add-controls">Controles</a> (já disponíveis em Painéis), guias de exploração de múltiplos dados, pesquisa em segundo plano, histórico de consultas mais completo e FUSE.</p><h2>Experimente o ES|QL hoje mesmo</h2><p>Você pode experimentar o ES|QL em projetos Elasticsearch <a href="https://www.elastic.co/cloud/serverless">Serverless</a> totalmente gerenciados com um <a href="https://www.elastic.co/docs/deploy-manage/deploy/elastic-cloud/create-serverless-project">período de avaliação gratuito</a>. Também está disponível em versões a partir da 8.11, mas a melhor experiência é obtida nas <a href="https://www.elastic.co/blog/whats-new-elastic-9-1-0">versões 8.19 e 9.1</a>.</p><p>Comece em minutos no seu ambiente local com um único comando:</p>curl -fsSL https://elastic.co/start-local | sh]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/opensearch-vs-elasticsearch-ppl-esql</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/opensearch-vs-elasticsearch-ppl-esql</guid>
    <category><![CDATA[ES|QL]]></category>
    <dc:creator><![CDATA[Libby Lin,George Kobar]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte51b193824ff8084/6a17f3257f6f154b7bc09c7c/f1ff4ff4a00b3e5b084d4116cea6cabc82a2d816-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Thu, 18 Sep 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Apresentamos o construtor de consultas ES|QL para o cliente Ruby do Elasticsearch.]]></title>
    <description><![CDATA[Aprenda a usar o construtor de consultas ES|QL recém-lançado para o cliente Ruby do Elasticsearch. Uma ferramenta para criar consultas ES|QL mais facilmente com código Ruby.]]></description>
    <content:encoded><![CDATA[<p>Recentemente lançamos <a href="https://github.com/elastic/esql-ruby/"><code>elastic-esql</code></a>, uma gem Ruby publicada sob a licença Apache 2. Esta gem permite que você crie consultas <a href="https://www.elastic.co/docs/explore-analyze/query-filter/languages/esql">ES|QL</a> da Elastic em Ruby idiomático, que você pode então usar com a API de consulta ES|QL. O ES|QL permite que os desenvolvedores filtrem, transformem e analisem dados armazenados no Elasticsearch por meio de consultas. Ele usa "pipes" ( <code>|</code> ) para trabalhar com os dados passo a passo. A gem usa funções Ruby, que você pode encadear ao objeto original para construir consultas mais complexas:</p><p><strong>ESQL:</strong></p><p><strong>Rubi:</strong></p>Elastic::ESQL.from('sample_data').limit(2).sort('@timestamp').descending<h2>Instalação</h2><p>A gem pode ser instalada a partir do RubyGems com o seguinte comando:</p>gem install elastic-esql<p>Ou pode ser adicionado ao Gemfile de um projeto:</p>gem 'elastic-esql'<h2>Uso</h2><p>Você pode construir uma consulta completa de uma só vez ou criar um objeto de consulta com um comando de origem como <code>from</code> ou <code>row</code> e, em seguida, encadear métodos ES|QL para construí-lo.</p>query = Elastic::ESQL.from('sample_data')
query.limit(2).sort('@timestamp')<p>A gem traduz o código para ES|QL no método <code>to_s</code> , portanto, retorna a consulta ES|QL quando é impressa ou convertida em uma String:</p>query = Elastic::ESQL.from('sample_data').limit(2).sort('@timestamp').descending
query.to_s
# =&gt; "FROM sample_data | LIMIT 2 | SORT @timestamp DESC"<p>Você pode instanciar um objeto de consulta e modificar seu estado inicial usando os equivalentes <code>!</code> de cada função:</p>query = Elastic::ESQL.from('sample_data')
query.to_s
# =&gt; "FROM sample_data"
query.limit!(2).sort!('@timestamp')
query.to_s
# =&gt; "FROM sample_data | LIMIT 2 | SORT @timestamp"<p>A ferramenta fornece maneiras convenientes de encadear etapas extras a uma função ES|QL, como <code>enrich</code> e <code>sort</code>. Depois de chamar <code>enrich</code> em um objeto <code>Elastic::ESQL</code> , você pode encadear <code>on</code> e <code>with</code> a ele:</p>esql.enrich!('policy').on('a').with({ name: 'language_name' })<p>Você também pode encadear <code>desc</code>, <code>asc</code>, <code>nulls_first</code> e <code>nulls_last</code> à sua consulta após usar <code>sort</code>:</p>Elastic::ESQL.from('sample_data').sort('@timestamp').asc.to_s
# =&gt; 'FROM sample_data | SORT @timestamp ASC'

Elastic::ESQL.from('sample_data').sort('@timestamp').desc.nulls_first.to_s
# =&gt; 'FROM sample_data | SORT @timestamp DESC NULLS FIRST'<p>Também oferece suporte a strings personalizadas, caso você queira escrever a consulta ES|QL por conta própria ou usar um recurso que ainda não foi adicionado à biblioteca. <code>custom</code> irá unir as strings no final da consulta. Isso os adicionará conforme forem enviados para a função, sem adicionar nenhum caractere de barra vertical. Eles serão combinados ao restante da consulta por um caractere de espaço.</p>esql = Elastic::ESQL.from('sample_data')
esql.custom('| MY_VALUE = "test value"').to_s
# =&gt; 'FROM sample_data | MY_VALUE = "test value"'<p>Você também pode encadear funções <code>custom</code> :</p>esql.custom('| MY_VALUE = "test value"').custom('| ANOTHER, VALUE')
'FROM sample_data | MY_VALUE = "test value" | ANOTHER, VALUE'<h2>Utilizando o Construtor de Consultas ES|QL com o cliente Ruby</h2><p>Você pode usar o construtor de consultas diretamente com <a href="https://github.com/elastic/elasticsearch-ruby">elasticsearch-ruby</a> e a API <code>esql.query</code> enviando o objeto de consulta:</p>require 'elasticsearch'
require 'elastic/esql'

client = Elasticsearch::Client.new
index = 'sample_data'

query = Elastic::ESQL.from(index)
                     .sort('@timestamp')
                     .desc
                     .where('event_duration &gt; 5000000')
                     .limit(3)
                     .eval({ duration_ms: 'ROUND(event_duration/1000000.0, 1)' })
client.esql.query(body: { query: query })<p>Você também pode usá-lo com o auxiliar ES|QL do cliente Ruby do Elasticsearch. <a href="https://www.elastic.co/search-labs/blog/esql-ruby-helper-elasticsearch">Saiba mais</a>:</p>require 'elasticsearch/helpers/esql_helper'

Elasticsearch::Helpers::ESQLHelper.query(client, query)<h2>Como uma ferramenta independente</h2><p>A gem foi projetada como uma ferramenta independente para construir consultas ES|QL de forma idiomática. Não possui dependências de tempo de execução; você pode usá-lo com o cliente oficial do Elasticsearch para Ruby ou de forma independente.</p><p>A consulta gerada pode ser usada com a API <a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-esql-query"><code>esql.query</code></a> de qualquer forma que um aplicativo interaja com a API do Elasticsearch (Ruby ou não). Uma vez que uma consulta é construída com <code>elastic-esql</code>, a String gerada pode ser enviada para a API como o parâmetro <code>query</code> no corpo da solicitação. </p><p>Anteriormente, escrevi sobre <a href="https://www.elastic.co/search-labs/blog/elasticsearch-ruby-tools">como usar o Elasticsearch com ferramentas populares do Ruby</a>. Esta gem pode ser usada com qualquer uma das ferramentas populares do Ruby para consultar o Elasticsearch com ES|QL.</p><h2>Conclusão</h2><p>Esta biblioteca está em desenvolvimento ativo e a API final ainda não foi concluída. Atualmente, está disponível em versão de pré-visualização técnica. Se você tiver algum comentário sobre a API atual ou sobre o uso em geral, não hesite em <a href="https://github.com/elastic/esql-ruby/issues">abrir uma nova solicitação</a>. Consulte <a href="https://github.com/elastic/esql-ruby/?tab=readme-ov-file#ruby-esql-query-builder">o arquivo README</a> para saber mais sobre o construtor de consultas Ruby ES|QL.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/esql-query-builder-elasticsearch-ruby-client</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/esql-query-builder-elasticsearch-ruby-client</guid>
    <category><![CDATA[ES|QL]]></category>
    <category><![CDATA[Ruby]]></category>
    <dc:creator><![CDATA[Fernando Briano]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt85d112ccca541b9e/6a17dccb4b055d6bfd4320cc/f8e1263ab53d356824a4fc539084151be80899db-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Wed, 17 Sep 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Ingerir dados geoespaciais no Elasticsearch com o Kibana para uso no ES|QL]]></title>
    <description><![CDATA[Como usar o Kibana e o processador de ingestão CSV para importar dados geoespaciais para o Elasticsearch para uso com pesquisa na Linguagem de Consulta Elasticsearch (ES|QL). O Elasticsearch possui recursos poderosos de busca geoespacial, que agora estão chegando ao ES|QL para uma facilidade de uso drasticamente aprimorada e familiaridade com o OGC. Mas para utilizar essas funcionalidades, precisamos de dados geoespaciais.]]></description>
    <content:encoded><![CDATA[<p>Recentemente publicamos um artigo no blog descrevendo como usar os novos <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">recursos</a> <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">de pesquisa geoespacial</a> <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">no ES|QL</a>, a nova e poderosa <a href="https://www.elastic.co/search-labs/blog/esql-piped-query-language-goes-ga">linguagem de consulta encadeada</a> do Elasticsearch. Para usar esses recursos, você precisa ter dados geoespaciais no Elasticsearch. Neste blog, mostraremos como importar dados geoespaciais e como usá-los em consultas ES|QL.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfc041ebca11476c6/6a16f70560084b31b93c4344/01fde3b1d714f12bf8673140c9f2f940d443de31-1440x823.jpg" alt="Pesquisa Geoespacial ESQL" /><h2>Importando dados geoespaciais usando o Kibana</h2><p>Os dados que usamos nos exemplos do blog anterior foram baseados em dados que usamos internamente para testes de integração. Para sua conveniência, incluímos aqui algumas informações em formato CSV que podem ser facilmente importadas usando o Kibana. Os dados são uma mistura de aeroportos, cidades e limites urbanos. Você pode baixar os dados de:</p><ul><li><p><a href="https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/supporting-blog-content/geospatial-data-ingest/airports/airports.csv">aeroportos.csv</a></p><ul><li><p>Este arquivo contém uma fusão de três conjuntos de dados:</p><ul><li><p>Aeroportos (nomes, localizações e dados relacionados) do <a href="https://www.naturalearthdata.com/downloads/10m-cultural-vectors/airports/">Natural Earth</a></p></li><li><p>Localização de cidades a partir <a href="https://simplemaps.com/data/world-cities">do SimpleMaps</a></p></li><li><p>Altitudes de aeroportos <a href="https://www.partow.net/miscellaneous/airportdatabase/">do banco de dados global de aeroportos</a></p></li></ul></li></ul></li><li><p><a href="https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/supporting-blog-content/geospatial-data-ingest/airports/airport_city_boundaries.csv">limites_cidade_aeroporto.csv</a></p><ul><li><p>Esta seção contém uma fusão dos nomes de aeroportos e cidades mencionados acima com uma nova fonte:</p><ul><li><p>Limites da cidade do <a href="https://www.openstreetmap.org/">OpenStreetMap</a></p></li></ul></li></ul></li></ul><p>Como você pode imaginar, dedicamos algum tempo a combinar essas fontes de dados nos dois arquivos acima, com o objetivo de poder testar os recursos geoespaciais do ES|QL. Isso pode não ser exatamente o que você precisa em termos de dados, mas espero que lhe dê uma ideia do que é possível. Em particular, queremos demonstrar algumas coisas interessantes:</p><ul><li><p>Importação de dados com campos geoespaciais juntamente com outros dados indexáveis.</p></li><li><p>Importar dados <code>geo_point</code> e <code>geo_shape</code> e usá-los em conjunto em consultas</p></li><li><p>Importar dados para dois índices que podem ser unidos usando uma relação espacial.</p></li><li><p>Criar um pipeline de ingestão para facilitar importações futuras (além do Kibana)</p></li><li><p>Alguns exemplos de processadores de ingestão, como <code>csv</code>, <code>convert</code> e <code>split</code></p></li></ul><p>Embora neste blog abordemos o trabalho com dados CSV, é importante entender que existem <a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">várias maneiras</a> <a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">de</a> <a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">adicionar dados geográficos usando</a> <a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">o Kibana</a>. No aplicativo Mapa, você pode carregar dados delimitados, como CSV, GeoJSON e ESRI ShapeFiles, e também pode desenhar formas diretamente no mapa. Neste blog, vamos nos concentrar na importação de arquivos CSV da página inicial do Kibana.</p><h3>Importando os aeroportos</h3><p>O primeiro arquivo, <a href="https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/supporting-blog-content/geospatial-data-ingest/airports/airports.csv">airports.csv</a>, Possui algumas peculiaridades interessantes com as quais precisamos lidar. Em primeiro lugar, as colunas possuem espaços em branco adicionais entre si, o que não é típico de arquivos CSV. Em segundo lugar, o campo <code>type</code> é um campo de múltiplos valores, que precisamos dividir em campos separados. Por fim, alguns campos não são strings e precisam ser convertidos para o tipo correto. Tudo isso pode ser feito usando o recurso de importação de CSV do Kibana.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt393bc416bf425301/6a16f707839dfa1e86dcfca9/b1afd8c95973bec32f229a9adfaef14680b09a8e-1944x478.png" alt="Upload do Kibana - Pré-visualização" /><p>Comece pela página inicial do Kibana. Existe uma seção chamada "Comece adicionando integrações", que possui um link chamado "Carregar um arquivo":</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte12fc741edab20d3/6a16f709acf088600fbe98bf/996372bb3a52859cc840bd1d8f984a33a0e7ada3-1180x410.png" alt="Página inicial do Kibana - Carregar um arquivo" /><p>Clique neste link e você será redirecionado para a página "Enviar arquivo". Aqui você pode arrastar e soltar o arquivo <code>airports.csv</code> , e o Kibana analisará o arquivo e apresentará uma pré-visualização dos dados. Deveria ter detectado automaticamente o delimitador como uma vírgula e a primeira linha como a linha de cabeçalho. No entanto, provavelmente não removeu o espaço em branco extra entre as colunas, nem determinou os tipos dos campos, assumindo que todos os campos são <code>text</code> ou <code>keyword</code>. Precisamos resolver isso.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf65a09ec0c7a61ad/6a16f70ad7c0227aedde626f/1d9ffa6cdbc0d67a228be1a747ec1ebda6a63099-1800x538.png" alt="Upload do Kibana - Pré-visualização" /><p>Clique em <code>Override settings</code> e marque a caixa de seleção para <code>Should trim fields</code> e <code>Apply</code> para fechar as configurações. Agora precisamos corrigir os tipos dos campos. Isso está disponível na próxima página, então clique em <code>Import</code>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltda9a5f85d8e693dc/6a16f70c60084b72f53c4348/a97aceffb1858eae26a213336913505ae9923b03-1800x526.png" alt="Carregar no Kibana - Importar" /><p>Primeiro escolha um nome de índice e, em seguida, selecione <code>Advanced</code> para acessar os mapeamentos de campo e a página do processador de ingestão.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt56705083cdd9eb18/6a16f70d66c4f93350f8bdbb/058b0fb09da0b8d7f9c9b0a9c83b8b485ce43925-1440x629.png" alt="Carregamento no Kibana - Mapeamento de campos" /><p>Aqui precisamos fazer alterações tanto no mapeamento de campos do índice quanto no pipeline de ingestão para importar os dados. Em primeiro lugar, embora o Kibana provavelmente tenha detectado automaticamente o campo <code>scalerank</code> como <code>long</code>, ele erroneamente percebeu os campos <code>location</code> e <code>city_location</code> como <code>keyword</code>. Edite-os para <code>geo_point</code>, resultando em mapeamentos que se parecem com algo assim:</p>{
  "properties": {
    "abbrev":        { "type": "keyword" },
    "city":          { "type": "keyword" },
    "city_location": { "type": "geo_point" },
    "country":       { "type": "keyword" },
    "elevation":     { "type": "double" },
    "location":      { "type": "geo_point" },
    "name":          { "type": "text" },
    "scalerank":     { "type": "long" },
    "type":          { "type": "keyword" }
  }
}<p>Você tem alguma flexibilidade aqui, mas observe que o tipo escolhido afetará a forma como o campo é indexado e os tipos de consultas possíveis. Por exemplo, se você deixar <code>location</code> como <code>keyword</code> não poderá realizar nenhuma consulta de pesquisa geoespacial nele. Da mesma forma, se você deixar <code>elevation</code> como <code>text</code> não poderá executar consultas de intervalo numérico nele.</p><p>Agora é hora de corrigir o pipeline de ingestão. Se o Kibana detectou automaticamente <code>scalerank</code> como <code>long</code> acima, ele também terá adicionado um processador para converter o campo em <code>long</code>. Precisamos adicionar um processador semelhante para o campo <code>elevation</code> , desta vez convertendo-o em <code>double</code>. Edite o pipeline para garantir que essa conversão esteja implementada. Antes de salvar isso, queremos mais uma conversão, para dividir o campo <code>type</code> em vários campos. Adicione um processador <code>split</code> ao pipeline, com a seguinte configuração:</p>{
  "split": {
    "field": "type",
    "separator": ":",
    "ignore_missing": true
  }
}<p>O pipeline de ingestão final deve ter a seguinte aparência:</p>{
  "description": "Ingest pipeline created by text structure finder",
  "processors": [
    {
      "csv": {
        "field": "message",
        "target_fields": [
          "abbrev",
          "name",
          "scalerank",
          "type",
          "location",
          "country",
          "city",
          "city_location",
          "elevation"
        ],
        "ignore_missing": false,
        "trim": true
      }
    },
    {
      "convert": {
        "field": "scalerank",
        "type": "long",
        "ignore_missing": true
      }
    },
    {
      "convert": {
        "field": "elevation",
        "type": "double",
        "ignore_missing": true
      }
    },
    {
      "split": {
        "field": "type",
        "separator": ":",
        "ignore_missing": true
      }
    },
    {
      "remove": {
        "field": "message"
      }
    }
  ]
}<p>Observe que não adicionamos um processador de conversão para os campos <code>location</code> e <code>city_location</code> . Isso ocorre porque o tipo <code>geo_point</code> no mapeamento de campo já entende o formato WKT dos dados nesses campos. O tipo <code>geo_point</code> pode entender uma variedade de formatos, incluindo <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-point.html">WKT, GeoJSON e outros</a>. Se tivéssemos, por exemplo, duas colunas no arquivo CSV para <code>latitude</code> e <code>longitude</code>, precisaríamos adicionar um processador <code>script</code> ou <code>set</code> para combiná-las em um único campo <code>geo_point</code> (por exemplo, <code>"set": {"field": "location", "value": "{{lat}},{{lon}}"}</code>).</p><p>Agora estamos prontos para importar o arquivo. Clique em <code>Import</code> e os dados serão importados para o índice com os mapeamentos e o pipeline de ingestão que acabamos de definir. Caso ocorram erros na ingestão dos dados, o Kibana os reportará aqui, para que você possa editar os dados de origem ou o pipeline de ingestão e tentar novamente.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte81621425c7289c5/6a16f70f839dfaf608dcfcad/55dde2940c7aba66ce8257d15007ef797b8a5107-1440x415.png" alt="Carregar no Kibana - Importando" /><p>Observe que um novo pipeline de ingestão foi criado. Isso pode ser visualizado indo para a seção <code>Stack Management</code> do Kibana e selecionando <code>Ingest pipelines</code>. Aqui você pode ver o pipeline que acabamos de criar e editá-lo, se necessário. Na verdade, a seção <code>Ingest pipelines</code> pode ser usada para criar e testar pipelines de ingestão, um recurso muito útil se você planeja fazer ingestões ainda mais complexas.</p><p>Se você deseja explorar esses dados imediatamente, pule para as seções posteriores, mas se também deseja importar os limites da cidade, continue lendo.</p><h3>Importando os limites da cidade</h3><p>O arquivo de limites da cidade disponível em <a href="https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/supporting-blog-content/geospatial-data-ingest/airports/airport_city_boundaries.csv">airport_city_boundaries.csv</a> é um pouco mais simples de importar do que o exemplo anterior. Contém um campo <code>city_boundary</code> que é uma representação WKT do limite da cidade como um <code>POLYGON</code> e um campo <code>city_location</code> que é uma representação <code>geo_point</code> da localização da cidade. Podemos importar esses dados de forma semelhante aos dados dos aeroportos, mas com algumas diferenças:</p><ul><li><p>Precisávamos selecionar a configuração de substituição <code>Has header row</code> pois ela não foi detectada automaticamente.</p></li><li><p>Não foi necessário remover espaços em branco dos campos, pois os dados já estavam livres de espaços desnecessários.</p></li><li><p>Não foi necessário editar o pipeline de ingestão, pois todos os tipos eram de string ou espaciais.</p></li><li><p>No entanto, tivemos que editar os mapeamentos de campo para definir o campo <code>city_boundary</code> como <code>geo_shape</code> e o campo <code>city_location</code> como . <code>geo_point</code></p></li></ul><p>Nossos mapeamentos de campo finais ficaram assim:</p>{
  "properties": {
    "abbrev":        { "type": "keyword" },
    "airport":       { "type": "keyword" },
    "city":          { "type": "keyword" },
    "city_boundary": { "type": "geo_shape" },
    "city_location": { "type": "geo_point" },
    "region":        { "type": "text" }
  }
}<p>Assim como na importação <code>airports.csv</code> anterior, basta clicar em <code>Import</code> para importar os dados para o índice. Os dados serão importados com os mapeamentos que editamos e o pipeline de ingestão definido pelo Kibana.</p><h3>Explorando dados geoespaciais com ferramentas de desenvolvimento</h3><p>No Kibana, é comum explorar os dados indexados com a opção "Descobrir". No entanto, se sua intenção é escrever seu próprio aplicativo usando consultas ES|QL, pode ser mais interessante tentar acessar a API Elasticsearch diretamente. O Kibana possui um console prático para experimentar a escrita de consultas. Isso é chamado de console <code>Dev Tools</code> e pode ser encontrado na barra lateral do Kibana. Este console se comunica diretamente com o cluster Elasticsearch e pode ser usado para executar consultas, criar índices e muito mais.</p><p>Experimente o seguinte:</p>POST /_query?error_trace=true&amp;format=txt
{
  "query": """
FROM airports
| EVAL distance = ST_DISTANCE(city_location, TO_GEOPOINT("POINT(12.565 55.673)"))
| WHERE distance &lt; 1000000 AND scalerank &lt; 6 AND distance &gt; 10000
| SORT distance ASC
| KEEP distance, abbrev, name, location, country, city, elevation
| LIMIT 10
  """
}<p>Isso deverá produzir os seguintes resultados:</p><p>distância</p><p>abreviar</p><p>nome</p><p>Local</p><p>país</p><p>cidade</p><p>elevação</p><p>273418.05776847183</p><p>PRESUNTO</p><p>Hamburgo</p><p>PONTO (10,005647830925 53,6320011640866)</p><p>Alemanha</p><p>Norderstedt</p><p>17.0</p><p>337534,653466062</p><p>TXL</p><p>Aeroporto Internacional de Berlim-Tegel</p><p>PONTO (13.2903090925074 52.5544287044101)</p><p>Alemanha</p><p>Hohen Neuendorf</p><p>38,0</p><p>483713.15032266214</p><p>OSL</p><p>Oslo Gardermoen</p><p>PONTO (11.0991032762581 60.1935783171386)</p><p>Noruega</p><p>Oslo</p><p>208,0</p><p>522538.03148094116</p><p>BMA</p><p>Broma</p><p>PONTO (17,9456175406145 59,3555902065112)</p><p>Suécia</p><p>Estocolmo</p><p>15.0</p><p>522538.03148094116</p><p>ARN</p><p>Arlanda</p><p>PONTO (17,9307299016916 59,6511203397372)</p><p>Suécia</p><p>Estocolmo</p><p>38,0</p><p>624274,8274399083</p><p>DUS</p><p>Aeroporto Internacional de Düsseldorf</p><p>PONTO (6,76494446612174 51,2781820420774)</p><p>Alemanha</p><p>Düsseldorf</p><p>45,0</p><p>633388,6966435644</p><p>PRG</p><p>Ruzyn</p><p>PONTO (14,2674849854076 50,1076511703671)</p><p>República Tcheca</p><p>Praga</p><p>381,0</p><p>635911.1873311149</p><p>AMS</p><p>Schiphol</p><p>PONTO (4,76437693232812 52,3089323889822)</p><p>Países Baixos</p><p>Hoofddorp</p><p>-3,0</p><p>670864.137958866</p><p>FRA</p><p>Frankfurt Internacional</p><p>PONTO (8,57182286907608 50,0506770895207)</p><p>Alemanha</p><p>Frankfurt</p><p>111.0</p><p>683239,2529970079</p><p>UAU</p><p>Okecie Int'l</p><p>PONTO (20,9727263383587 52,171026749259)</p><p>Polônia</p><p>Piaseczno</p><p>111.0</p><h2>Visualizando dados geoespaciais com o Kibana Maps</h2><p>O Kibana Maps é uma ferramenta poderosa para visualizar dados geoespaciais. Pode ser usado para criar mapas com múltiplas camadas, cada camada representando um conjunto de dados diferente. Os dados podem ser filtrados, agregados e formatados de diversas maneiras. Nesta seção, mostraremos como criar um mapa no Kibana Maps usando os dados que importamos na seção anterior.</p><p>No menu do Kibana, navegue até <code>Analytics</code>-&gt;<code>Maps</code> para abrir uma nova visualização do mapa. Clique em <code>Add Layer</code> e selecione <code>Documents</code>, escolhendo a visualização de dados <code>airports</code> e editando o estilo da camada para colorir os marcadores usando o campo <code>elevation</code> , para que possamos ver facilmente a altitude de cada aeroporto.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdcc4736d88c1abc9/6a16f7102b835f7353f4afca/9e63726d7c059331e6e20e474f8abee53dc2cbb4-840x388.png" alt="Kibana Maps - Estilo de Camada de Aeroportos" /><p>Clique em "Manter alterações" para salvar o mapa:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8ec3cc535b5c21d8/6a16f71375879ec091fe15dc/32ad1dadb5d341a2b66662c58638b781122fc22c-2852x1528.png" alt="Mapas do Kibana - Aeroportos" /><p>Agora adicione uma segunda camada, desta vez selecionando a visualização de dados <code>airport_city_boundaries</code> . Desta vez, usaremos o campo <code>city_boundary</code> para estilizar a camada e definiremos a cor de preenchimento para um azul claro. Isso mostrará os limites da cidade no mapa. Certifique-se de reordenar as camadas para garantir que os marcadores do aeroporto fiquem por cima.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2932d7ff4a7206c9/6a16f7156f7f0409f09145c7/53dd65026f9a98c13f2cc4f9328a79242f0b70de-2854x1510.png" alt="Kibana Maps - Estilo de Camada de Limites da Cidade" /><h2>Junções espaciais</h2><p>ES|QL não suporta comandos <code>JOIN</code> , mas você pode realizar um caso especial de junção usando o <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-commands.html#esql-enrich">comando</a> <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-commands.html#esql-enrich"><code>ENRICH</code></a> . Este comando funciona de forma semelhante a uma 'junção à esquerda' em SQL, permitindo enriquecer os resultados de um índice com dados de outro índice com base em uma relação espacial entre os dois conjuntos de dados.</p><p>Por exemplo, vamos enriquecer os resultados de uma tabela de aeroportos com informações adicionais sobre a cidade que eles atendem, encontrando o limite da cidade que contém a localização do aeroporto e, em seguida, realizar algumas análises estatísticas dos resultados:</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary
| STATS
    centroid = ST_CENTROID_AGG(location),
    count = COUNT(city_location)
    BY region
| SORT count DESC
| LIMIT 10<p>Se você executar essa consulta sem primeiro preparar o índice de enriquecimento, receberá uma mensagem de erro como esta:</p>cannot find enrich policy [city_boundaries]<p>Isso ocorre porque, como mencionamos anteriormente, o ES|QL não suporta comandos <code>JOIN</code> verdadeiros. Um motivo importante para isso é que o Elasticsearch é um sistema distribuído, e as junções são operações custosas e difíceis de escalar. No entanto, o comando <code>ENRICH</code> pode ser bastante eficiente, porque utiliza índices enriquecidos especialmente preparados que são duplicados em todo o cluster, permitindo que junções locais sejam realizadas em cada nó.</p><p>Para melhor compreender isso, vamos nos concentrar no comando <code>ENRICH</code> na consulta acima:</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary<p>Este comando instrui o Elasticsearch a enriquecer os resultados recuperados do índice <code>airports</code> e a realizar uma junção <code>intersects</code> entre o campo <code>city_location</code> do índice original e o campo <code>city_boundary</code> do índice <code>airport_city_boundaries</code> , que usamos em alguns exemplos anteriores. Mas algumas dessas informações não estão claramente visíveis nesta consulta. O que vemos é o nome de uma política de enriquecimento <code>city_boundaries</code> e a informação em falta está encapsulada na definição dessa política.</p>{
  "geo_match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}<p>Aqui podemos ver que ele executará uma consulta <code>geo_match</code> (<code>intersects</code> é o padrão), o campo para comparar é <code>city_boundary</code> e os <code>enrich_fields</code> são os campos que queremos adicionar ao documento original. Um desses campos, o <code>region</code> foi na verdade usado como chave de agrupamento para o comando <code>STATS</code> , algo que não poderíamos ter feito sem essa capacidade de 'junção à esquerda'. Para obter mais informações sobre políticas de enriquecimento, consulte a <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/enrich-setup.html">documentação de enriquecimento</a>.</p><p>Os índices e políticas de enriquecimento no Elasticsearch foram originalmente projetados para enriquecer dados no momento da indexação, usando dados de outro índice de enriquecimento já preparado. Em ES|QL, no entanto, o comando <code>ENRICH</code> funciona no momento da consulta e não requer o uso de pipelines de ingestão. Isso efetivamente o torna bastante semelhante a um SQL <code>LEFT JOIN</code>, exceto que você não pode unir quaisquer dois índices, apenas um índice normal à esquerda com um índice enriquecido especialmente preparado à direita.</p><p>Em ambos os casos, seja para pipelines de ingestão ou para uso no ES|QL, é necessário executar algumas etapas preparatórias para configurar o índice e a política de enriquecimento. Já importamos o índice <code>airport_city_boundaries</code> acima, mas este não é diretamente utilizável como um índice de enriquecimento no comando <code>ENRICH</code> . Primeiro, precisamos realizar duas etapas:</p><ul><li><p>Crie a política de enriquecimento descrita acima para definir o índice de origem, o campo no índice de origem a ser comparado e os campos a serem retornados após a correspondência.</p></li><li><p>Execute esta política para criar o índice de enriquecimento. Isso criará um índice interno especial, lendo o índice de origem original para uma estrutura de dados mais eficiente, que será copiada em todo o cluster.</p></li></ul><p>A política de enriquecimento pode ser criada usando o seguinte comando:</p>PUT /_enrich/policy/city_boundaries
{
  "match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}<p>E a política pode ser executada usando o seguinte comando:</p>POST /_enrich/policy/city_boundaries/_execute<p>Observe que, se você alterar o conteúdo do índice <code>airport_city_boundaries</code> , precisará executar esta política novamente para ver as alterações refletidas no índice enriquecido. Agora, vamos executar a consulta ES|QL original novamente:</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary
| STATS
    centroid = ST_CENTROID_AGG(location),
    count = COUNT(city_location)
    BY region
| SORT count DESC
| LIMIT 10<p>Isso retorna as 5 principais regiões com o maior número de aeroportos, juntamente com o centroide de todos os aeroportos que possuem regiões correspondentes e o intervalo de comprimento da representação WKT dos limites das cidades dentro dessas regiões:</p><p>centroide</p><p>Contagem</p><p>região</p><p>PONTO (-12.139086859300733 31.024386116624648)</p><p>126</p><p>nulo</p><p>PONTO (-83.10398317873478 42.300230911932886)</p><p>3</p><p>Detroit</p><p>PONTO (39,74537850357592 47,21613017376512)</p><p>3</p><p>городской округ Батайск</p><p>PONTO (-156,80986787192523 20,476673701778054)</p><p>3</p><p>Havaí</p><p>PONTO (-73,94515332765877 40,70366442203522)</p><p>3</p><p>Cidade de Nova York</p><p>PONTO (-83.10398317873478 42.300230911932886)</p><p>3</p><p>Detroit</p><p>PONTO (-76,66873019188643 24.306286952923983)</p><p>2</p><p>Nova Providência</p><p>PONTO (-3,0252167768776417 51,39245774131268)</p><p>2</p><p>Cardiff</p><p>PONTO (-115,40993484668434 32,73126147687435)</p><p>2</p><p>Município de Mexicali</p><p>PONTO (41,790108773857355 50,302146775648)</p><p>2</p><p>Área Central</p><p>PONTO (-73,88902732171118 45.57078813901171)</p><p>2</p><p>Montreal</p><p>Você também pode notar que a região mais comumente encontrada foi <code>null</code>. O que isso poderia implicar? Lembre-se de que comparei este comando a um 'left join' em SQL, o que significa que se nenhum limite de cidade correspondente for encontrado para um aeroporto, o aeroporto ainda será retornado, mas com valores <code>null</code> para os campos do índice <code>airport_city_boundaries</code> . Descobriu-se que havia 125 aeroportos que não encontraram nenhum <code>city_boundary</code> correspondente e um aeroporto com uma correspondência onde o campo <code>region</code> era <code>null</code>. Isso levou a uma contagem de 126 aeroportos sem nenhum <code>region</code> nos resultados. Se o seu caso de uso exigir que todos os aeroportos possam ser associados aos limites de uma cidade, isso exigirá a obtenção de dados adicionais para preencher as lacunas. Seria necessário determinar duas coisas:</p><ul><li><p>quais registros no índice <code>airport_city_boundaries</code> não possuem campos <code>city_boundary</code></p></li><li><p>quais registros no índice <code>airports</code> não correspondem usando o comando <code>ENRICH</code> (ou seja, não se cruzam)</p></li></ul><h2>Utilizando ES|QL para dados geoespaciais em mapas do Kibana</h2><p>O Kibana adicionou suporte para Spatial ES|QL no aplicativo Maps. Isso significa que agora você pode usar o ES|QL para pesquisar dados geoespaciais no Elasticsearch e visualizar os resultados em um mapa.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt91922eb4ef43d290/6a16f7161949f737bfe7a7b5/bd78470bd8a4bc60f0db7006bd804b8fe87e2fea-1440x683.png" alt="Camadas do Kibana ES|QL" /><p>Existe uma nova opção de camada no menu "Adicionar camadas", chamada "ES|QL". Assim como todos os recursos geoespaciais descritos até agora, este está em "prévia técnica". Selecionar esta opção permite adicionar uma camada ao mapa com base nos resultados de uma consulta ES|QL. Por exemplo, você poderia adicionar uma camada ao mapa que mostrasse todos os aeroportos do mundo.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5185ef7461d7e81d/6a16f718839dfa1559dcfcb1/1dd28d3d0509f92d26b0bb5320a2925f7a54c5d9-1440x736.png" alt="Kibana ES|QL - Aeroportos" /><p>Ou você poderia adicionar uma camada que mostre os polígonos do índice <code>airport_city_boundaries</code> , ou ainda melhor, que tal aquela consulta complexa <code>ENRICH</code> acima que gera estatísticas de quantos aeroportos existem em cada região?</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt51ee3543bb811d98/6a16f71a8b73cbbe63189df1/679a0a401faa613c7cedddd07c64f614ac2b7144-1440x727.png" alt="Kibana ES|QL - Estatísticas da região" /><h2>O que vem a seguir?</h2><p>O blog anterior <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">sobre pesquisa geoespacial</a> focou no uso de funções como <code>ST_INTERSECTS</code> para realizar pesquisas, disponíveis no Elasticsearch desde a versão 8.14. E este blog mostra como importar os dados que usamos nessas pesquisas. No entanto, o Elasticsearch 8.15 trouxe uma função particularmente interessante: <code>ST_DISTANCE</code> que pode ser usada para realizar pesquisas eficientes de distância espacial, e este será o tema do próximo blog!</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/geospatial-data-ingest-for-esql</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/geospatial-data-ingest-for-esql</guid>
    <category><![CDATA[Kibana]]></category>
    <category><![CDATA[ES|QL]]></category>
    <dc:creator><![CDATA[Craig Taverner]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfc041ebca11476c6/6a16f70560084b31b93c4344/01fde3b1d714f12bf8673140c9f2f940d443de31-1440x823.jpg" length="0" type="image/jpeg"/>
    <pubDate>Fri, 25 Oct 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Pesquisa geoespacial do Elasticsearch com ES|QL]]></title>
    <description><![CDATA[Pesquisa geoespacial na linguagem de consulta Elasticsearch (ES|QL). O Elasticsearch possui recursos poderosos de busca geoespacial, que agora estão chegando ao ES|QL para uma facilidade de uso drasticamente aprimorada e familiaridade com o OGC.]]></description>
    <content:encoded><![CDATA[<p>O Elasticsearch possui <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/geospatial-analysis.html">recursos poderosos de busca e análise geoespacial</a> há muitos anos, mas a API era bastante diferente daquilo a que os usuários típicos de SIG estavam acostumados. No último ano <a href="https://www.elastic.co/search-labs/blog/esql-piped-query-language-goes-ga">, adicionamos a linguagem de consulta ES|QL</a>, uma linguagem de consulta encadeada tão fácil, ou até mais fácil, que o SQL. É particularmente adequado para os casos de uso de busca, segurança e observabilidade nos quais o Elastic se destaca. Também estamos adicionando suporte para pesquisa e análise geoespacial no ES|QL, tornando-o muito mais fácil de usar, especialmente para usuários vindos das comunidades SQL ou <a href="https://en.wikipedia.org/wiki/Geographic_information_system">GIS</a> .</p><p>O Elasticsearch 8.12 e 8.13 trouxeram suporte básico para tipos geoespaciais ao ES|QL. Isso foi significativamente aprimorado com a adição de recursos de busca geoespacial na versão 8.14. Mais importante ainda, esse suporte foi projetado para estar em estrita conformidade com o padrão <a href="https://en.wikipedia.org/wiki/Simple_Features">Simple Feature Access</a> do <a href="https://en.wikipedia.org/wiki/Open_Geospatial_Consortium">Open Geospatial Consortium (OGC),</a> usado por outros bancos de dados espaciais como o PostGIS, tornando-o muito mais fácil de usar para especialistas em SIG familiarizados com esses padrões.</p><p>Neste blog, mostraremos como usar o ES|QL para realizar buscas geoespaciais e como ele se compara aos seus equivalentes em SQL e Query DSL. Também mostraremos como usar o ES|QL para realizar junções espaciais e como visualizar os resultados no Kibana Maps. Note que todos os recursos descritos aqui estão em "prévia técnica" e gostaríamos muito de receber seu feedback sobre como podemos melhorá-los.</p><h2>Pesquisa de dados geoespaciais</h2><p>Vamos começar com um exemplo de consulta:</p>FROM airport_city_boundaries
| WHERE ST_INTERSECTS(
      city_boundary,
      "POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))"::geo_shape
  )
| KEEP abbrev, airport, region, city, city_location
<p>Esta função realiza uma busca por quaisquer polígonos de limites urbanos que se intersectem com um polígono de busca retangular ao redor do Aeroporto Internacional de Sanya Phoenix (SYX).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3897df6bed5d6061/6a17d7c2abe0f29eccdfe861/e48bac8f246c8842f2ea97ddd54910045262aeb1-1440x808.png" alt="Pesquisa Geoespacial ESQL" /><p>Em um conjunto de dados de exemplo contendo aeroportos, cidades e limites urbanos, esta busca encontra o polígono de interseção e retorna os campos desejados do documento correspondente:</p><p>abreviar</p><p>aeroporto</p><p>região</p><p>cidade</p><p>localização da cidade</p><p>SYX</p><p>Sanya Phoenix Int'l</p><p>天涯区</p><p>Sanya</p><p>PONTO(109,5036 18,2533)</p><p>Isso foi fácil! Agora compare isso com a DSL de consulta clássica do Elasticsearch para a mesma consulta:</p>GET /airport_city_boundaries/_search
{
  "_source": ["abbrev", "airport", "region", "city", "city_location"],
  "query": {
    "geo_shape": {
      "city_boundary": {
        "shape": {
          "type": "polygon",
          "coordinates" : [[
            [109.4, 18.1],
            [109.6, 18.1],
            [109.6, 18.3],
            [109.4, 18.3],
            [109.4, 18.1]
          ]]
        }
      }
    }
  }
}
<p>Ambas as consultas são razoavelmente claras em sua intenção, mas a consulta ES|QL se assemelha bastante ao SQL. A mesma consulta no PostGIS se parece com isto:</p>SELECT abbrev, airport, region, city, city_location
FROM airport_city_boundaries
WHERE ST_INTERSECTS(
    city_boundary,
    'SRID=4326;POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))'::geometry
);
<p>Relembre o exemplo em ES|QL. São muito parecidos, não é?</p>FROM airport_city_boundaries
| WHERE ST_INTERSECTS(
      city_boundary,
      "POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))"::geo_shape
  )
| KEEP abbrev, airport, region, city, city_location
<p>Constatamos que os usuários existentes da API Elasticsearch consideram o ES|QL muito mais fácil de usar. Agora, esperamos que os usuários atuais de SQL, especialmente os usuários de SQL Espacial, achem o ES|QL muito familiar ao que já estão acostumados a ver.</p><h4>Por que não usar SQL?</h4><p>E quanto ao Elasticsearch SQL? Já existe há algum tempo e possui algumas funcionalidades geoespaciais. No entanto, o Elasticsearch SQL foi escrito como um wrapper sobre a API de consulta original, o que significa que apenas as consultas que podiam ser transpiladas para a API original eram suportadas. ES|QL não possui essa limitação. Por ser uma pilha de tecnologias completamente nova, permite muitas otimizações que não eram possíveis em SQL. Nossos testes de desempenho mostram que o ES|QL é <a href="https://elasticsearch-benchmarks.elastic.co/#tracks/esql/nightly/default/6M">frequentemente mais rápido que a API de consulta</a>, principalmente em operações de agregação!</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt18bda964c8b24e36/6a17d7c3e3179155d22d568a/b8b6c2b2e45850d832805ed1e71e522f4955f53c-1440x813.png" alt="referência de interseção de polígonos" /><h2>Diferenças em relação ao SQL</h2><p>Claramente, pelo exemplo anterior, o ES|QL é de certa forma semelhante ao SQL, mas existem algumas diferenças importantes. Por exemplo, ES|QL é uma linguagem de consulta encadeada, começando com um comando de origem como FROM e, em seguida, encadeando todos os comandos subsequentes com o caractere pipe |. Isso torna muito fácil entender como cada comando recebe uma tabela de dados e realiza alguma ação nessa tabela, como filtrar com <code>WHERE</code>, adicionar colunas com <code>EVAL</code> ou realizar agregações com <code>STATS</code>. Em vez de começar com <code>SELECT</code> para definir as colunas de saída finais, pode haver um ou mais comandos <code>KEEP</code> , com o último especificando os resultados de saída finais. Essa estrutura simplifica o raciocínio sobre a consulta.</p><p>Analisando o comando <code>WHERE</code> no exemplo acima, podemos ver que ele é bastante semelhante ao exemplo do PostGIS:</p><p><em>ES|QL</em></p>WHERE ST_INTERSECTS(
    city_boundary,
    "POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))"::geo_shape
)
<p><em>PostGIS</em></p>WHERE ST_INTERSECTS(
    city_boundary,
    'SRID=4326;POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))'::geometry
)
<p>Além da diferença nos caracteres de aspas da string, a maior diferença está em como convertemos a string para um tipo espacial. No PostGIS, usamos o sufixo <code>::geometry</code> , enquanto no ES|QL, usamos o sufixo <code>::geo_shape</code> . Isso ocorre porque o ES|QL é executado dentro do Elasticsearch e o operador de conversão de tipo <code>::</code> pode ser usado para converter uma string em qualquer um dos <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-limitations.html#_supported_types">tipos ES|QL suportados</a>, neste caso, um <code>geo_shape</code>. Além disso, os tipos <code>geo_shape</code> e <code>geo_point</code> no Elasticsearch implicam o sistema de coordenadas espaciais conhecido como WGS84, mais comumente referido usando o número SRID 4326. No PostGIS, isso precisa ser explícito, daí o uso do prefixo <code>SRID=4326;</code> na string WKT. Se esse prefixo for removido, o SRID será definido como 0, que é mais parecido com os tipos do Elasticsearch <code>cartesian_point</code> e <code>cartesian_shape</code>, que não estão vinculados a nenhum sistema de coordenadas específico.</p><p>Tanto o ES|QL quanto o PostGIS também fornecem sintaxe para funções de conversão de tipo:</p><p><em>ES|QL</em></p>WHERE ST_INTERSECTS(
    city_boundary,
    TO_GEOSHAPE("POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))")
)
<p><em>PostGIS</em></p>WHERE ST_INTERSECTS(
    city_boundary,
    ST_SetSRID(
      ST_GeomFromText('POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))'),
      4326
    )
)
<h2>Funções OGC</h2><p>O Elasticsearch 8.14 introduz as seguintes quatro funções de pesquisa espacial OGC:</p><p>ES|QL</p><p>PostGIS</p><p>Descrição</p><p>ST_INTERSETOS</p><p>ST_Interseções</p><p>Retorna verdadeiro se duas geometrias se intersectam e falso caso contrário.</p><p>ST_DISJOINT</p><p>ST_Disjunto</p><p>Retorna verdadeiro se as duas geometrias não se intersectarem e falso caso contrário. O inverso de ST_INTERSETOS.</p><p>ST_CONTÉM</p><p>ST_Contém</p><p>Retorna verdadeiro se uma geometria contém outra, e falso caso contrário.</p><p>ST_DENTRO</p><p>ST_Dentro</p><p>Retorna verdadeiro se uma geometria estiver dentro de outra, e falso caso contrário. O inverso de ST_CONTAINS.</p><p>Essas funções se comportam de maneira semelhante às suas contrapartes no PostGIS e são usadas da mesma forma. Por exemplo, <code>ST_INTERSECTS</code> retorna verdadeiro se duas geometrias se intersectam e falso caso contrário. Se você seguir os links de documentação na tabela acima, poderá notar que todos os exemplos ES|QL estão dentro de uma cláusula <code>WHERE</code> após uma cláusula <code>FROM</code> , enquanto todos os exemplos PostGIS estão usando geometrias literais. Na verdade, ambas as plataformas suportam o uso das funções em qualquer parte da consulta onde façam sentido.</p><p>O primeiro exemplo na documentação do PostGIS para <code>ST_INTERSECTS</code> é:</p>SELECT ST_Intersects(
    'POINT(0 0)'::geometry,
    'LINESTRING ( 2 0, 0 2 )'::geometry
);
<p>O equivalente em ES|QL seria:</p>ROW ST_INTERSECTS(
    "POINT(0 0)"::geo_point,
    "LINESTRING ( 2 0, 0 2 )"::geo_shape
)
<p>Observe que não especificamos o SRID no exemplo do PostGIS. Isso ocorre porque no PostGIS, ao usar o tipo <code>geometry</code> , todos os cálculos são feitos em um sistema de coordenadas planas e, portanto, se ambas as geometrias tiverem o mesmo SRID, não importa qual seja o SRID. No Elasticsearch, isso também é verdade para a maioria das funções, no entanto, existem exceções onde <code>geo_shape</code> e <code>geo_point</code> usam cálculos esféricos, como veremos no próximo blog sobre pesquisa de distância espacial.</p><h2>Versatilidade ES|QL</h2><p>Então, vimos exemplos acima de uso de funções espaciais em cláusulas <code>WHERE</code> e em comandos <code>ROW</code> . Em que outro lugar fariam sentido? Um local muito útil é no comando <code>EVAL</code> . Este comando permite avaliar uma expressão e retornar o resultado. Por exemplo, vamos determinar se os centroides de todos os aeroportos agrupados por seus nomes de país estão dentro de um limite que delimita o país:</p>FROM airports
| EVAL in_uk = ST_INTERSECTS(location, TO_GEOSHAPE("POLYGON((1.2305 60.8449, -1.582 61.6899, -10.7227 58.4017, -7.1191 55.3291, -7.9102 54.2139, -5.4492 54.0078, -5.2734 52.3756, -7.8223 49.6676, -5.0977 49.2678, 0.9668 50.5134, 2.5488 52.1065, 2.6367 54.0078, -0.9668 56.4625, 1.2305 60.8449))"))
| EVAL in_iceland = ST_INTERSECTS(location, TO_GEOSHAPE("POLYGON ((-25.4883 65.5312, -23.4668 66.7746, -18.4131 67.4749, -13.0957 66.2669, -12.3926 64.4159, -20.1270 62.7346, -24.7852 63.3718, -25.4883 65.5312))"))
| EVAL within_uk = ST_WITHIN(location, TO_GEOSHAPE("POLYGON((1.2305 60.8449, -1.582 61.6899, -10.7227 58.4017, -7.1191 55.3291, -7.9102 54.2139, -5.4492 54.0078, -5.2734 52.3756, -7.8223 49.6676, -5.0977 49.2678, 0.9668 50.5134, 2.5488 52.1065, 2.6367 54.0078, -0.9668 56.4625, 1.2305 60.8449))"))
| EVAL within_iceland = ST_WITHIN(location, TO_GEOSHAPE("POLYGON ((-25.4883 65.5312, -23.4668 66.7746, -18.4131 67.4749, -13.0957 66.2669, -12.3926 64.4159, -20.1270 62.7346, -24.7852 63.3718, -25.4883 65.5312))"))
| STATS centroid = ST_CENTROID_AGG(location), count=COUNT() BY in_uk, in_iceland, within_uk, within_iceland
| SORT count ASC
<p>Os resultados são os esperados: o centroide dos aeroportos do Reino Unido está dentro das fronteiras do Reino Unido, e não dentro das fronteiras da Islândia, e vice-versa.</p><p>centroide</p><p>Contagem</p><p>no Reino Unido</p><p>na Islândia</p><p>dentro do Reino Unido</p><p>dentro da Islândia</p><p>PONTO (-21,946634463965893 64.13187285885215)</p><p>1</p><p>falso</p><p>verdadeiro</p><p>falso</p><p>verdadeiro</p><p>PONTO (-2,597342072712148 54,33551226578214)</p><p>17</p><p>verdadeiro</p><p>falso</p><p>verdadeiro</p><p>falso</p><p>PONTO (0,04453958108176276 23,74658354606057)</p><p>873</p><p>falso</p><p>falso</p><p>falso</p><p>falso</p><p>Na verdade, essas funções podem ser usadas em qualquer parte da consulta onde sua assinatura faça sentido. Todas elas recebem dois argumentos, que podem ser um objeto espacial literal ou um campo de um tipo espacial, e todas retornam um valor booleano. Uma consideração importante é que o sistema de referência de coordenadas (SRC) das geometrias deve coincidir, caso contrário, será retornado um erro. Isso significa que você não pode misturar os tipos <code>geo_shape</code> e <code>cartesian_shape</code> na mesma chamada de função. Você pode, no entanto, misturar os tipos <code>geo_point</code> e <code>geo_shape</code> , já que o tipo <code>geo_point</code> é um caso especial do tipo <code>geo_shape</code> e ambos compartilham o mesmo sistema de referência de coordenadas. A documentação de cada uma das funções definidas acima lista as combinações de tipos suportadas.</p><p>Além disso, qualquer um dos argumentos pode ser um literal espacial ou um campo, em qualquer ordem. Você pode até especificar dois campos, dois literais, um campo e um literal, ou um literal e um campo. O único requisito é que os tipos sejam compatíveis. Por exemplo, esta consulta compara dois campos no mesmo índice:</p>FROM airport_city_boundaries
| EVAL in_city = ST_INTERSECTS(city_location, city_boundary)
| STATS count=COUNT(*) BY in_city
| SORT count ASC
| EVAL cardinality = CASE(count &lt; 10, "very few", count &lt; 100, "few", "many")
| KEEP cardinality, count, in_city
<p>A consulta basicamente pergunta se a localização da cidade está dentro dos limites da cidade, o que geralmente deve ser verdade, mas sempre há exceções:</p><p>cardinalidade</p><p>Contagem</p><p>na cidade</p><p>alguns</p><p>29</p><p>falso</p><p>muitos</p><p>740</p><p>verdadeiro</p><p>Uma questão muito mais interessante seria saber se a localização do aeroporto está dentro dos limites da cidade que ele serve. No entanto, a localização do aeroporto reside em um índice diferente daquele que contém os limites da cidade. Isso requer um método para consultar e correlacionar dados de forma eficaz a partir desses dois índices separados.</p><h2>Junções espaciais</h2><p>ES|QL não suporta comandos <code>JOIN</code> , mas você pode obter um caso especial de junção usando o<a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-commands.html#esql-enrich"> comando</a> <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-commands.html#esql-enrich"><code>ENRICH</code></a> , que se comporta de forma semelhante a uma 'junção esquerda' em SQL. Este comando funciona de forma semelhante a uma 'junção à esquerda' em SQL, permitindo enriquecer os resultados de um índice com dados de outro índice com base em uma relação espacial entre os dois conjuntos de dados.</p><p>Por exemplo, vamos enriquecer os resultados de uma tabela de aeroportos com informações adicionais sobre a cidade que eles atendem, encontrando o limite da cidade que contém a localização do aeroporto e, em seguida, realizar algumas análises estatísticas dos resultados:</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary
| MV_EXPAND city_boundary
| EVAL boundary_wkt_length = LENGTH(TO_STRING(city_boundary))
| STATS centroid = ST_CENTROID_AGG(location), count = COUNT(city_location), min_wkt = MIN(boundary_wkt_length), max_wkt = MAX(boundary_wkt_length) BY region
| SORT count DESC
| LIMIT 5
<p>Isso retorna as 5 principais regiões com o maior número de aeroportos, juntamente com o centroide de todos os aeroportos que possuem regiões correspondentes e o intervalo de comprimento da representação WKT dos limites das cidades dentro dessas regiões:</p><p>centroide</p><p>Contagem</p><p>min_wkt</p><p>max_wkt</p><p>região</p><p>PONTO (-32,56093470960719 32,598117914802714)</p><p>90</p><p>207</p><p>207</p><p>nulo</p><p>PONTO (-73,94515332765877 40,70366442203522)</p><p>9</p><p>438</p><p>438</p><p>Cidade de Nova York</p><p>PONTO (-83.10398317873478 42.300230911932886)</p><p>9</p><p>473</p><p>473</p><p>Detroit</p><p>PONTO (-156.3020245861262 20,176383580081165)</p><p>5</p><p>307</p><p>803</p><p>Havaí</p><p>PONTO (-73,88902732171118 45.57078813901171)</p><p>4</p><p>837</p><p>837</p><p>Montreal</p><p>Então, o que realmente aconteceu aqui? Onde ocorreu o suposto <code>JOIN</code> ? O ponto crucial da questão reside no comando <code>ENRICH</code> :</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary
<p>Este comando instrui o Elasticsearch a enriquecer os resultados recuperados do índice <code>airports</code> e a realizar uma junção <code>intersects</code> entre o campo <code>city_location</code> do índice original e o campo <code>city_boundary</code> do índice <code>airport_city_boundaries</code> , que usamos em alguns exemplos anteriores. Mas algumas dessas informações não estão claramente visíveis nesta consulta. O que vemos é o nome de uma política de enriquecimento <code>city_boundaries</code> e a informação em falta está encapsulada na definição dessa política.</p>{
  "geo_match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}
<p>Aqui podemos ver que ele executará uma consulta <code>geo_match</code> (<code>intersects</code> é o padrão), o campo para comparar é <code>city_boundary</code> e os <code>enrich_fields</code> são os campos que queremos adicionar ao documento original. Um desses campos, o <code>region</code> foi na verdade usado como chave de agrupamento para o comando <code>STATS</code> , algo que não poderíamos ter feito sem essa capacidade de 'junção à esquerda'. Para obter mais informações sobre políticas de enriquecimento, consulte a <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/enrich-setup.html">documentação de enriquecimento</a>. Ao ler esses documentos, você notará que eles descrevem o uso de índices de enriquecimento para enriquecer dados no momento da indexação, configurando pipelines de ingestão. Isso não é necessário para ES|QL, pois o comando <code>ENRICH</code> funciona no momento da consulta. Basta preparar o índice de enriquecimento com os dados necessários e a política de enriquecimento e, em seguida, usar o comando <code>ENRICH</code> em suas consultas ES|QL.</p><p>Você também pode notar que a região mais comumente encontrada foi <code>null</code>. O que isso poderia implicar? Lembre-se de que comparei este comando a um 'left join' em SQL, o que significa que se nenhum limite de cidade correspondente for encontrado para um aeroporto, o aeroporto ainda será retornado, mas com valores <code>null</code> para os campos do índice <code>airport_city_boundaries</code> . Descobriu-se que havia 89 aeroportos que não encontraram nenhum <code>city_boundary</code> correspondente e um aeroporto com uma correspondência onde o campo <code>region</code> era <code>null</code>. Isso levou a uma contagem de 90 aeroportos sem nenhum <code>region</code> nos resultados. Outro detalhe interessante é a necessidade do comando <code>MV_EXPAND</code> . Isso é necessário porque o comando <code>ENRICH</code> pode retornar vários resultados para cada linha de entrada e <code>MV_EXPAND</code> ajuda a separar esses resultados em várias linhas, uma para cada resultado. Isso também esclarece por que "Havaí" mostra resultados diferentes <code>min_wkt</code> e <code>max_wkt</code> : havia várias regiões com o mesmo nome, mas limites diferentes.</p><h2>Mapas do Kibana</h2><p>O Kibana adicionou suporte para Spatial ES|QL no aplicativo Maps. Isso significa que agora você pode usar o ES|QL para pesquisar dados geoespaciais no Elasticsearch e visualizar os resultados em um mapa.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt91922eb4ef43d290/6a16f7161949f737bfe7a7b5/bd78470bd8a4bc60f0db7006bd804b8fe87e2fea-1440x683.png" alt="Camadas do Kibana ES|QL" /><p>Existe uma nova opção de camada no menu "Adicionar camadas", chamada "ES|QL". Assim como todos os recursos geoespaciais descritos até agora, este está em "prévia técnica". Selecionar esta opção permite adicionar uma camada ao mapa com base nos resultados de uma consulta ES|QL. Por exemplo, você poderia adicionar uma camada ao mapa que mostrasse todos os aeroportos do mundo.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5185ef7461d7e81d/6a16f718839dfa1559dcfcb1/1dd28d3d0509f92d26b0bb5320a2925f7a54c5d9-1440x736.png" alt="Kibana ES|QL - Aeroportos" /><p>Ou você poderia adicionar uma camada que mostre os polígonos do índice <code>airport_city_boundaries</code> , ou ainda melhor, que tal aquela consulta complexa <code>ENRICH</code> acima que gera estatísticas de quantos aeroportos existem em cada região?</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt51ee3543bb811d98/6a16f71a8b73cbbe63189df1/679a0a401faa613c7cedddd07c64f614ac2b7144-1440x727.png" alt="Kibana ES|QL - Estatísticas da região" /><h2>O que vem a seguir?</h2><p>Você deve ter notado que em dois dos exemplos acima incluímos mais uma função espacial <code>ST_CENTROID_AGG</code>. Esta é uma função de agregação usada no comando <code>STATS</code> e a primeira de muitas funcionalidades de análise espacial que planejamos adicionar ao ES|QL. Vamos publicar um artigo sobre isso quando tivermos mais informações para mostrar!</p><p>Antes disso, gostaríamos de falar mais sobre um recurso particularmente interessante no qual trabalhamos: a capacidade de realizar buscas por distância espacial, um dos recursos de busca espacial mais utilizados do Elasticsearch. Você consegue imaginar como seria a sintaxe para buscas por distância? Talvez semelhante a uma função OGC? Fique ligado(a) no próximo post desta série para descobrir!</p><p>Alerta de spoiler: o Elasticsearch 8.15 acaba de ser lançado e inclui pesquisa por distância espacial com ES|QL!</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one</guid>
    <category><![CDATA[Python]]></category>
    <category><![CDATA[ES|QL]]></category>
    <dc:creator><![CDATA[Craig Taverner]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd05627be20e89dfb/6a17d7c6414c640256944fdb/de886289dcb56494920875303b622b030b9b810f-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Mon, 12 Aug 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[De objetos ES|QL para PHP]]></title>
    <description><![CDATA[Aprenda como executar e gerenciar consultas ES|QL em PHP. Siga este guia para mapear resultados ES|QL para um objeto PHP ou classe personalizada.]]></description>
    <content:encoded><![CDATA[<p>A partir da <a href="https://github.com/elastic/elasticsearch-php/releases/tag/v8.13.0">versão 8.13.0</a> do elasticsearch-php, você pode executar consultas <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html">ES|QL</a> e mapear o resultado para um objeto PHP da <a href="https://www.php.net/manual/en/class.stdclass.php">classe padrão (stdClass)</a> ou de uma classe personalizada.</p><h2>ES|QL</h2><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html">ES|QL</a> é uma nova linguagem de consulta do Elasticsearch introduzida na versão 8.11.0. Neste momento, está disponível em versão de pré-visualização técnica. Ele oferece uma maneira poderosa de filtrar, transformar e analisar dados armazenados no Elasticsearch.</p><p>Ele utiliza "pipes" (<code>|</code>) para manipular e transformar dados passo a passo. Essa abordagem permite aos usuários compor uma série de operações, onde o resultado de uma operação se torna a entrada para a próxima, possibilitando transformações e análises de dados complexas.</p><p>Por exemplo, a seguinte consulta retorna os 3 primeiros documentos (linhas) do índice <code>sample_data</code> :</p>FROM sample_data
| LIMIT 3
<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8b0310cb335872b7/6a17d7eab1e113258679f0df/c23aee777bacdf90c63b717fd9458207dfc0511d-864x284.png" alt="ES|QL produz tabelas" /><h2>Caso de uso: recursos ES|QL no cliente PHP oficial</h2><p>Para ilustrar os recursos do ES|QL desenvolvidos no cliente PHP oficial, armazenamos no Elasticsearch um <a href="https://github.com/elastic/elasticsearch-php-examples/blob/main/examples/ESQL/data/books.csv">arquivo CSV</a> com 81.828 livros (54,4 MB) contendo as seguintes informações:</p>Title;Descrition;Author;Year;Publisher;Ratings
<p>Extraímos esta lista do <a href="https://www.kaggle.com/datasets/mohamedbakhet/amazon-books-reviews">conjunto de dados público de avaliações de livros da Amazon</a>.</p><p>Criamos um índice <code>books</code> com os seguintes mapeamentos do Elasticsearch:</p>'mappings' : {
    'properties': {
        'title': {
            'type': 'text'
        },
        'description': {
            'type': 'text'
        },
        'author': {
            'type': 'text'
        },
        'year': {
            'type': 'short'
        },
        'publisher': {
            'type': 'keyword'
        },
        'rating': {
            'type': 'half_float'
        }
    }
}
<p>O valor <code>rating</code> é a média das classificações das avaliações extraídas do arquivo <a href="https://www.kaggle.com/datasets/mohamedbakhet/amazon-books-reviews?select=Books_rating.csv">Books_rating.csv</a> de 2,9 GB.</p><p><a href="https://github.com/elastic/elasticsearch-php-examples/blob/main/examples/ESQL/bulk.php">Aqui</a> você encontra o script PHP que usamos para importar todos os livros em massa para o Elasticsearch. A operação em lote levou 7 segundos e consumiu 28 MB de RAM usando o PHP 8.2.17. Com o mapeamento proposto, o tamanho do índice no Elasticsearch é de aproximadamente 62 MB.</p><h2>Mapear resultados ES|QL para um objeto PHP ou classe personalizada</h2><p>Podemos executar uma consulta ES|QL em PHP usando o endpoint <code>esql()-&gt;query()</code> . O resultado desta consulta é uma estrutura de dados em forma de tabela. Isso é expresso em JSON usando os campos <code>columns</code> e <code>values</code> . No campo <code>columns</code> temos a definição <code>name</code> e <code>type</code> .</p><p>Aqui está um exemplo de consulta ES|QL para recuperar os 10 melhores livros escritos por Stephen King, ordenados pela classificação das avaliações dos usuários:</p>$query = &lt;&lt;&lt;EOD
    FROM books
    | WHERE author == "Stephen King"
    | SORT rating DESC
    | LIMIT 10
EOD;

$result = $client-&gt;esql()-&gt;query([
    'body' =&gt; ['query' =&gt; $query]
]);
<p>O resultado JSON do Elasticsearch tem a seguinte aparência:</p>{
    "columns": [
        { "name": "author", "type": "text" },
        { "name": "description", "type": "text" },
        { "name": "publisher", "type": "keyword" },
        { "name": "rating", "type": "double" },
        { "name": "title", "type": "text" },
        { "name": "year", "type": "integer" }
    ],
    "values": [
        [
            "Stephen King",
            "The author ...",
            "Turtleback",
            5.0,
            "How writers write",
            2002
        ],
        [
            "Stephen King",
            "In Blockade Billy, a retired coach...",
            "Simon and Schuster",
            5.0,
            "Blockade",
            2010
        ],
        [
            "Stephen King",
            "A chilling collection of twenty horror stories.",
            "Signet Book",
            4.55859375,
            "Night Shift (Signet)",
            1979
        ],
        ...
    ]
}
<p>Neste exemplo, temos 6 propriedades (autor, descrição, editora, classificação, título, ano) relacionadas a um livro e 10 resultados, todos livros de Stephen King.</p><p>Uma lista de todos os tipos suportados em ES|QL é apresentada <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-limitations.html#esql-supported-types">aqui</a>.</p><p>O objeto de resposta <code>$result</code> pode ser acessado como uma matriz, uma string ou como um objeto (veja <a href="https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/connecting.html#client-usage">aqui</a> para mais informações).</p><p>Utilizando a interface de objeto, podemos acessar os valores por meio de propriedades e índices. Por exemplo, <code>$result-&gt;values[0][4]</code> retorna o título (4) do primeiro livro (0) da lista, <code>$result-&gt;values[1][3]</code> retorna a pontuação de classificação (3) do segundo livro (1), etc. Lembre-se, o índice de um array em PHP começa em zero.</p><p>Essa interface pode ser suficiente para alguns casos de uso, mas na maioria das vezes preferimos obter um array de objetos como resultado.</p><p>Para mapear o resultado em uma matriz de objetos, podemos usar o novo recurso <a href="https://github.com/elastic/elasticsearch-php/issues/1398">mapTo()</a> do elasticsearch-php.</p><p>Essa função está disponível diretamente no <a href="https://github.com/elastic/elasticsearch-php/blob/main/src/Response/Elasticsearch.php">objeto de resposta do Elasticsearch</a>. Isso significa que você pode acessá-lo da seguinte forma:</p>$books = $result-&gt;mapTo(); // Array of stdClass
foreach ($books as $book) {
    printf(
        "%s, %s, %d, Rating: %.2f\n",
        $book-&gt;author,
        $book-&gt;title,
        $book-&gt;year,
        $book-&gt;rating
    );
}
<p>Se você tiver uma classe Book personalizada, poderá mapear o resultado usando-a, da seguinte forma:</p>class Book
{
    public string $author;
    public string $title;
    public string $description;
    public int $year;
    public float $rating;
}

$books = $result-&gt;mapTo(Book::class); // Array of Book
<p>Se sua classe tiver outras propriedades além das incluídas no resultado ES|QL, isso também funcionará. A função <code>mapTo()</code> usará apenas as propriedades retornadas como colunas do resultado ES|QL.</p><p>Você pode baixar todos os exemplos relatados neste artigo <a href="https://github.com/elastic/elasticsearch-php-examples/tree/main/examples/ESQL">aqui</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/esql-php-map-object-class</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/esql-php-map-object-class</guid>
    <category><![CDATA[ES|QL]]></category>
    <category><![CDATA[PHP]]></category>
    <dc:creator><![CDATA[Enrico Zimuel]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt99f5ab85c0713977/6a17d7ebfbc5f8072b491918/aea56270f48cb64130d1b515b983434e0960dc2f-500x500.png" length="0" type="image/png"/>
    <pubDate>Mon, 08 Apr 2024 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>