<?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[Go - 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[Go - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/es/search-labs/blog/category/go-programming</link>
    </image>
    <link>https://www.elastic.co/es/search-labs/blog/category/go-programming</link>
    <atom:link href="https://www.elastic.co/es/search-labs/rss/category/go-programming.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[es]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 06:31:17 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Usar búsqueda híbrida para la detección de errores con Elasticsearch y Go]]></title>
    <description><![CDATA[Aprende cómo lograr búsqueda híbrida combinando búsqueda por palabras clave y vectorial usando Elasticsearch y el cliente Elasticsearch Go.]]></description>
    <content:encoded><![CDATA[<p>En las partes anteriores de este serial, se demostró cómo usar el cliente Elasticsearch Go para <a href="https://www.elastic.co/search-labs/blog/perform-text-queries-with-the-elasticsearch-go-client">la búsqueda tradicional por palabras clave</a> y <a href="https://www.elastic.co/search-labs/blog/perform-vector-search-with-the-elasticsearch-go-client">la búsqueda vectorial</a>. Esta tercera parte trata sobre la búsqueda híbrida. Compartiremos <a href="https://github.com/carlyrichmond/gopher-hunting-elasticsearch">ejemplos</a> de cómo puedes combinar tanto búsqueda vectorial como búsqueda por palabras clave usando <a href="https://www.elastic.co/elasticsearch/">Elasticsearch</a> y el <a href="https://www.elastic.co/guide/en/elasticsearch/client/go-api/current/index.html">cliente Elasticsearch Go</a>.</p><h2>Prerrequisitos</h2><p>Al igual que en la primera parte de este serial, se requieren los siguientes requisitos previos para este ejemplo:</p><ol><li><p>Instalación de Go versión 1.21 o posterior</p></li><li><p>Crea tu propio repositorio de Go usando la estructura recomendada y la gestión de paquetes que se menciona en la <a href="https://go.dev/doc/code">documentación de Go</a></p></li><li><p>Creando tu propio clúster de Elasticsearch, poblado con un conjunto de <a href="https://github.com/carlyrichmond/gopher-hunting-elasticsearch#sources">páginas basadas en roedores</a>, incluyendo nuestro amigable <a href="https://en.wikipedia.org/wiki/Gopher">Gopher</a>, de Wikipedia:</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6a436c42996e5172/6a1704cf0c48573d1c01a957/34fa81a9b4c292634c719b8303a9b6b7506d7920-1440x662.png" alt="Página de Wikipedia sobre los Topos" /><h2>Conexión con Elasticsearch</h2><p>Como recordatorio, en nuestros ejemplos emplearemos la <a href="https://www.elastic.co/guide/en/elasticsearch/client/go-api/current/typedapi.html">API</a> tipada que ofrece el cliente Go. Establecer una conexión segura para cualquier consulta requiere configurar al cliente usando cualquiera de:</p><ol><li><p>ID de la nube y clave API si se emplea Elastic Cloud</p></li><li><p>URL del clúster, nombre de usuario, contraseña y el certificado</p></li></ol><p>Conectarse a nuestro clúster ubicado en Elastic Cloud sería así:</p>func GetElasticsearchClient() (*elasticsearch.TypedClient, error) {
	var cloudID = os.Getenv("ELASTIC_CLOUD_ID")
	var apiKey = os.Getenv("ELASTIC_API_KEY")

	var es, err = elasticsearch.NewTypedClient(elasticsearch.Config{
		CloudID: cloudID,
		APIKey:  apiKey,
		Logger:  &amp;elastictransport.ColorLogger{os.Stdout, true, true},
	})

	if err != nil {
		return nil, fmt.Errorf("unable to connect: %w", err)
	}

	return es, nil
}
<p>La conexión <code>client</code> puede entonces emplear para búsqueda, como se demuestra en las secciones posteriores.</p><h2>Impulso manual para búsqueda híbrida</h2><p>Al combinar cualquier conjunto de algoritmos de búsqueda, el enfoque tradicional fue configurar manualmente las constantes para potenciar cada tipo de consulta. Específicamente, se especifica un factor para cada consulta, y el conjunto de resultados combinados se compara con el conjunto esperado para determinar la recuperación de la consulta. Luego repetimos para varios conjuntos de factores y elegimos el que esté más cerca de nuestro estado deseado.</p><p>Por ejemplo, combinar una consulta de búsqueda de texto individual potenciada por un factor de <code>0.8</code> con una consulta knn de menor factor de <code>0.2</code> puede hacer especificando el campo <code>Boost</code> en ambos tipos de consulta, como se muestra en el siguiente ejemplo:</p>func HybridSearchWithBoost(client *elasticsearch.TypedClient, term string) ([]Rodent, error) {
	var k = 10
	var numCandidates = 10
	var knnBoost float32 = 0.2
	var queryBoost float32 = 0.8

	res, err := client.Search().
		Index("vector-search-rodents").
		Knn(types.KnnSearch{
			Field:         "text_embedding.predicted_value",
			Boost:         &amp;knnBoost,
			K:             &amp;k,
			NumCandidates: &amp;numCandidates,
			QueryVectorBuilder: &amp;types.QueryVectorBuilder{
				TextEmbedding: &amp;types.TextEmbedding{
					ModelId:   "sentence-transformers__msmarco-minilm-l-12-v3",
					ModelText: term,
				},
			}}).
		Query(&amp;types.Query{
			Match: map[string]types.MatchQuery{
				"title": {
					Query: term,
					Boost: &amp;queryBoost,
				},
			},
		}).
		Do(context.Background())

	if err != nil {
		return nil, err
	}

	return getRodents(res.Hits.Hits)
}
<p>El factor especificado en la opción de <code>Boost</code> para cada consulta se suma al puntaje del documento. Al aumentar el puntaje de nuestra consulta de coincidencia en un factor mayor que la consulta knn, los resultados de la consulta por palabra clave tienen un peso más fuerte.</p><p>El reto del aumento manual, especialmente si no eres un experto en búsquedas, es que requiere ajuste para identificar los factores que manejarán al conjunto de resultados deseado. Simplemente se trata de probar valores aleatorios para ver qué te acerca más al conjunto de resultados deseado.</p><h2>Fusión de rangos recíprocos en un cliente híbrido de búsqueda y Go</h2><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/rrf.html">Reciprocal Rank Fusion</a>, o RRF, se publicó en formato de vista previa técnica para búsqueda híbrida en Elasticsearch 8.9. Su objetivo es reducir la curva de aprendizaje asociada al ajuste y disminuir el tiempo dedicado a experimentar con factores para optimizar el conjunto de resultados.</p><p>Con RRF, el puntaje del documento se recalcula mezclando los puntajes mediante el siguiente algoritmo:</p>score := 0.0
// q is a query in the set of queries (vector and keyword search)
for _, q := range queries {
    // result(q) is the results 
    if document in result(q) {
        // k is a ranking constant (default 60)
        // rank(result(q), d) is the document's rank within result(q) 
        // range from 1 to the window_size (default 100)
        score +=  1.0 / (k + rank(result(q), d))
    }
}

return score
<p>El beneficio de usar RRF es que podemos aprovechar los valores predeterminados sensatos dentro de Elasticsearch. La constante de clasificación <code>k</code> por defecto es <code>60</code>. Para proporcionar un equilibrio entre la relevancia de los documentos devueltos y el rendimiento de la consulta al buscar sobre grandes conjuntos de datos, el tamaño del conjunto de resultados para cada consulta considerada se limita al valor de <code>window_size</code>, que por defecto es <code>100</code> según se indica en la <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/rrf.html#rrf-api">documentación</a>.</p><p><code>k</code> y <code>windows_size</code> también pueden configurar dentro de la configuración <code>Rrf</code> dentro del método <code>Rank</code> en el cliente Go, como se muestra en el siguiente ejemplo:</p>func HybridSearchWithRRF(client *elasticsearch.TypedClient, term string) ([]Rodent, error) {
	var k = 10
	var numCandidates = 10

	// Minimum required window size for the default result size of 10
	var windowSize int64 = 10
	var rankConstant int64 = 42

	res, err := client.Search().
		Index("vector-search-rodents").
		Knn(types.KnnSearch{
			Field:         "text_embedding.predicted_value",
			K:             &amp;k,
			NumCandidates: &amp;numCandidates,
			QueryVectorBuilder: &amp;types.QueryVectorBuilder{
				TextEmbedding: &amp;types.TextEmbedding{
					ModelId:   "sentence-transformers__msmarco-minilm-l-12-v3",
					ModelText: term,
				},
			}}).
		Query(&amp;types.Query{
			Match: map[string]types.MatchQuery{
				"title": {Query: term},
			},
		}).
		Rank(&amp;types.RankContainer{
			Rrf: &amp;types.RrfRank{
				WindowSize:   &amp;windowSize,
				RankConstant: &amp;rankConstant,
			},
		}).
		Do(context.Background())

	if err != nil {
		return nil, err
	}

	return getRodents(res.Hits.Hits)
}
<h2>Conclusión</h2><p>Aquí hablamos de cómo combinar la búsqueda vectorial y la búsqueda por palabras clave en Elasticsearch usando el <a href="https://www.elastic.co/guide/en/elasticsearch/client/go-api/current/index.html">cliente Elasticsearch Go</a>.</p><p>Echa un vistazo al <a href="https://github.com/carlyrichmond/gopher-hunting-elasticsearch">repositorio de GitHub</a> para ver todo el código de este serial. Si no lo hiciste ya, echa un vistazo a <a href="https://www.elastic.co/search-labs/blog/perform-text-queries-with-the-elasticsearch-go-client">la parte 1</a> y <a href="https://www.elastic.co/search-labs/blog/perform-vector-search-with-the-elasticsearch-go-client">la parte 2</a> para ver todo el código de este serial.</p><p><em>¡Feliz caza de topos!</em></p><h2>Recursos</h2><ol><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html">Guía Elasticsearch</a></p></li><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/client/go-api/current/index.html">Cliente Elasticsearch Go</a></p></li><li><p><a href="https://www.elastic.co/what-is/vector-search">¿Qué es la búsqueda vectorial? | Elástico</a></p></li><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/rrf.html">Fusión recíproca de rangos</a></p></li></ol>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/hybrid-search-with-the-elasticsearch-go-client</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/hybrid-search-with-the-elasticsearch-go-client</guid>
    <category><![CDATA[Base de datos vectorial]]></category>
    <category><![CDATA[Go]]></category>
    <dc:creator><![CDATA[Carly Richmond,Laurent Saint-Félix]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdcae959696d55a9b/6a1704d5ab7f085a56db9d7c/491ef9efbb30b253e1d9e3b7f816a9a23c8f5264-721x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Thu, 02 Nov 2023 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Realiza búsqueda vectorial en Elasticsearch con el cliente Elasticsearch Go]]></title>
    <description><![CDATA[Aprende a realizar búsqueda vectorial en Elasticsearch usando el cliente Elasticsearch Go a través de un ejemplo práctico.]]></description>
    <content:encoded><![CDATA[<p>Desarrollar software en cualquier lenguaje de programación, incluido Go, es comprometer con una vida entera de aprendizaje. A lo largo de su carrera universitaria y profesional, Carly experimentó con muchos lenguajes de programación y tecnologías, incluyendo las últimas y mejores implementaciones de búsqueda vectorial. ¡Pero eso no fue suficiente! Así que recientemente Carly también empezó a jugar con Go.</p><p>Al igual que los animales, los lenguajes de programación y tu autor amable, la búsqueda experimentó una evolución de diferentes prácticas que pueden ser difíciles de elegir para tu propio caso de uso. En este blog, compartiremos una visión general de la búsqueda vectorial junto con <a href="https://github.com/carlyrichmond/gopher-hunting-elasticsearch">ejemplos</a> de cada enfoque usando <a href="https://www.elastic.co/elasticsearch/">Elasticsearch</a> y el <a href="https://www.elastic.co/guide/en/elasticsearch/client/go-api/current/index.html">cliente Elasticsearch Go</a>. Estos ejemplos te mostrarán cómo encontrar topos y determinar qué comen usando búsqueda vectorial en Elasticsearch y Go.</p><h2>Prerrequisitos</h2><p>Para seguir con este ejemplo, cerciorar de cumplir los siguientes requisitos:</p><ol><li><p>Instalación de Go versión 1.21 o posterior</p></li><li><p>Creación de tu propio repositorio Go con el</p></li><li><p>Creación de tu propio clúster Elasticsearch, poblado con un conjunto de páginas basadas en roedores, incluyendo para nuestro <a href="https://en.wikipedia.org/wiki/Gopher">amable Gopher</a>, de Wikipedia:</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6a436c42996e5172/6a1704cf0c48573d1c01a957/34fa81a9b4c292634c719b8303a9b6b7506d7920-1440x662.png" alt="Página de Wikipedia sobre los Topos" /><h2>Conexión con Elasticsearch</h2><p>En nuestros ejemplos, emplearemos la <a href="https://www.elastic.co/guide/en/elasticsearch/client/go-api/current/typedapi.html">API tipada</a> que ofrece el cliente Go. Establecer una conexión segura para cualquier consulta requiere configurar al cliente usando cualquiera de:</p><ol><li><p>Cloud ID y clave API si se emplea Elastic Cloud.</p></li><li><p>URL del clúster, nombre de usuario, contraseña y el certificado.</p></li></ol><p>Conectarse a nuestro clúster ubicado en Elastic Cloud sería así:</p>func GetElasticsearchClient() (*elasticsearch.TypedClient, error) {
	var cloudID = os.Getenv("ELASTIC_CLOUD_ID")
	var apiKey = os.Getenv("ELASTIC_API_KEY")

	var es, err = elasticsearch.NewTypedClient(elasticsearch.Config{
		CloudID: cloudID,
		APIKey:  apiKey,
		Logger:  &amp;elastictransport.ColorLogger{os.Stdout, true, true},
	})

	if err != nil {
		return nil, fmt.Errorf("unable to connect: %w", err)
	}

	return es, nil
}
<p>La conexión <code>client</code> puede entonces emplear para búsqueda vectorial, como se muestra en secciones posteriores.</p><h2>Búsqueda de vectores</h2><p>La búsqueda vectorial intenta resolver este problema convirtiendo el problema de búsqueda en una comparación matemática usando vectores. El proceso de incrustación de documentos tiene una etapa adicional de convertir el documento usando un modelo en una representación vectorial densa, o simplemente en un flujo de números. El beneficio de este enfoque es que puedes buscar documentos no textuales, como imágenes y audio, traduciéndolos a un vector junto con una consulta.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc4b3b9b2ad1e8f46/6a1704d06234e0800fdb1927/b113358093e367358d684f7aaf0a6684ebb2d0dd-1440x653.png" alt="Diagrama de búsqueda vectorial" /><p>En términos simples, la búsqueda vectorial es un conjunto de cálculos de distancia vectorial. En la ilustración siguiente, la representación vectorial de nuestro <code>Go Gopher</code>de consulta se compara con los documentos en el espacio vectorial, y se devuelven los resultados más cercanos (denotados por <code>k</code>constantes):</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5c736ecfc49bb038/6a1704d2cf4f25bcb6b2d075/54a17a4b41029644e7c66f33d428e8d01a6f4ce3-1184x743.png" alt="Ejemplo de espacio vectorial de topo" /><p>Dependiendo del método que se emplee para generar los embeddings de tus documentos, hay dos formas diferentes de saber qué comen los topos.</p><h3>Enfoque 1: Trae tu propio modelo</h3><p>Con una licencia Platinum, es posible generar las incrustaciones dentro de Elasticsearch subiendo el modelo y usando la API de inferencia. Hay seis pasos implicados para establecer el modelo:</p><ol><li><p>Selecciona un modelo de PyTorch para subirlo desde un repositorio de modelos. Para este ejemplo, estamos usando <a href="https://huggingface.co/sentence-transformers/msmarco-MiniLM-L-12-v3">los transformadores de frase/msmarco-MiniLM-L-12-v3</a> de Hugging Face para generar los embeddings.</p></li><li><p>Carga el modelo en Elastic usando el <a href="https://www.elastic.co/guide/en/elasticsearch/client/eland/current/overview.html">cliente Eland Machine Learning para Python</a> usando las credenciales de nuestro clúster Elasticsearch y tipo de tarea <code>text_embeddings</code>. Si no tienes Eland instalado, puedes <a href="https://www.elastic.co/guide/en/machine-learning/current/ml-nlp-import-model.html#ml-nlp-import-docker">ejecutar el paso de importación usando Docker</a>, como se muestra a continuación:</p></li></ol>docker run -it --rm --network host \
    docker.elastic.co/eland/eland \
    eland_import_hub_model \
      --cloud-id $ELASTIC_CLOUD_ID \
      --es-api-key $ELASTIC_API_KEY \
      --hub-model-id sentence-transformers/msmarco-MiniLM-L-12-v3 \
      --task-type text_embedding
<ol><li><p>Una vez cargado, prueba rápidamente el <code>sentence-transformers__msmarco-minilm-l-12-v3</code> del modelo con un documento de muestra para cerciorarte de que las incrustaciones se generan como se espera:</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8a399e1f50ecfdaf/6a1704d4ab7f08935edb9d78/fbbdde621361a487eb07304bed029c228d0f7aa6-1440x789.png" alt="Ejemplo de modelo capacitado por pruebas elásticas" /><ol><li><p>Crear una tubería de ingesta que contenga un procesador de inferencia. Esto permitirá generar la representación vectorial usando el modelo subido:</p></li></ol>PUT _ingest/pipeline/search-rodents-vector-embedding-pipeline
{
  "processors": [
    {
      "inference": {
        "model_id": "sentence-transformers__msmarco-minilm-l-12-v3",
        "target_field": "text_embedding",
        "field_map": {
          "body_content": "text_field"
        }
      }
    }
  ]
}
<ol><li><p>Crea un nuevo índice que contenga el <code>text_embedding.predicted_value</code> de campo de tipo <code>dense_vector</code> para almacenar las incrustaciones vectoriales generadas para cada documento:</p></li></ol>PUT vector-search-rodents
{
  "mappings": {
    "properties": {
      "text_embedding.predicted_value": {
        "type": "dense_vector",
        "dims": 384,
        "index": true,
        "similarity": "cosine"
      },
      "text": {
        "type": "text"
      }
    }
  }
}
<ol><li><p>Reindexa los documentos usando la nueva tubería de ingesta para generar las incrustaciones de texto como el campo adicional <code>text_embedding.predicted_value</code> en cada documento:</p></li></ol>POST _reindex
{
  "source": {
    "index": "search-rodents"
  },
  "dest": {
    "index": "vector-search-rodents",
    "pipeline": "search-rodents-vector-embedding-pipeline"
  }
}
<p>Ahora podemos usar la opción <code>Knn</code> en la misma API de búsqueda usando el nuevo índice <code>vector-search-rodents</code>, como se muestra en el siguiente ejemplo:</p>func VectorSearch(client *elasticsearch.TypedClient, term string) ([]Rodent, error) {
  var k = 10
	var numCandidates = 10

	res, err := client.Search().
		Index("vector-search-rodents").
		Knn(types.KnnSearch{
      # Field in document containing vector
			Field:         "text_embedding.predicted_value",
      # Number of neighbors to return
			K:             &amp;k,
      # Number of candidates to evaluate in comparison
			NumCandidates: &amp;numCandidates,
      # Generate query vector using the same model used in the inference processor
			QueryVectorBuilder: &amp;types.QueryVectorBuilder{
				TextEmbedding: &amp;types.TextEmbedding{
					ModelId:   "sentence-transformers__msmarco-minilm-l-12-v3",
					ModelText: term,
				},
			}}).Do(context.Background())

	if err != nil {
		return nil, fmt.Errorf("error in rodents vector search: %w", err)
	}

	return getRodents(res.Hits.Hits)
}
<p>La conversión del objeto de resultado JSON mediante desmaravillamiento se realiza exactamente de la misma manera que en el ejemplo de búsqueda por palabra clave. Las constantes <code>K</code> y <code>NumCandidates</code> nos permiten configurar el número de documentos vecinos que devolver y el número de candidatos a considerar por fragmento. Ten en cuenta que aumentar el número de candidatos incrementa la precisión de los resultados pero conduce a una consulta de mayor duración a medida que se realizan más comparaciones.</p><p>Cuando el código se ejecuta usando la consulta <code>What do Gophers eat?</code>, los resultados devuelto se ven similares a los siguientes, destacando que el artículo de Gopher contiene la información aplicar, a diferencia de la búsqueda por palabra clave anterior:</p>[
  {ID:64f74ecd4acb3df024d91112 Title:Gopher - Wikipedia Url:https://en.wikipedia.org/wiki/Gopher} 
  {ID:64f74ed34acb3d71aed91fcd Title:Squirrel - Wikipedia Url:https://en.wikipedia.org/wiki/Squirrel} 
  //Other results omitted
]
<h3>Enfoque 2: API de inferencia de rostros de abrazo</h3><p>Otra opción es generar estas mismas incrustaciones fuera de Elasticsearch e ingerirlas como parte de tu documento. Como esta opción no emplea un nodo de aprendizaje automático de Elasticsearch, puede hacer en la capa libre.</p><p>Hugging Face expone una <a href="https://huggingface.co/docs/api-inference/index">API de inferencia</a> gratis y limitada a la velocidad que, con una cuenta y un token de API, puede usar para generar manualmente las mismas incrustaciones para experimentación y prototipado que te ayude a empezar. No se recomienda para uso en producción. Invocar tus propios modelos localmente para generar embeddings o usar la API de pago también puede hacer con un enfoque similar.</p><p>En la función <code>GetTextEmbeddingForQuery</code> siguiente usamos la API de inferencia contra nuestra cadena de consulta para generar el vector devuelto de una petición <code>POST</code> al punto final:</p>// HuggingFace text embedding helper
func GetTextEmbeddingForQuery(term string) []float32 {
    // HTTP endpoint
    model := "sentence-transformers/msmarco-minilm-l-12-v3"
    posturl := fmt.Sprintf("https://api-inference.huggingface.co/pipeline/feature-extraction/%s", model)

    // JSON body
    body := []byte(fmt.Sprintf(`{
        "inputs": "%s",
        "options": {"wait_for_model":True}
    }`, term))

    // Create a HTTP post request
    r, err := http.NewRequest("POST", posturl, bytes.NewBuffer(body))

    if err != nil {
        log.Fatal(err)
        return nil
    }

    token := os.Getenv("HUGGING_FACE_TOKEN")
    r.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))

    client := &amp;http.Client{}
    res, err := client.Do(r)
    if err != nil {
        panic(err)
    }

    defer res.Body.Close()

    var post []float32
    derr := json.NewDecoder(res.Body).Decode(&amp;post)

    if derr != nil {
        log.Fatal(derr)
        return nil
    }

    return post
}
<p>El vector resultante, de tipo <code>[]float32</code> , se pasa entonces como <code>QueryVector</code> en lugar de usar la opción <code>QueryVectorBuilder</code> para aprovechar el modelo previamente subido a Elastic.</p>func VectorSearchWithGeneratedQueryVector(client *elasticsearch.TypedClient, term string) ([]Rodent, error) {
	vector, err := GetTextEmbeddingForQuery(term)
	if err != nil {
		return nil, err
	}

	if vector == nil {
		return nil, fmt.Errorf("unable to generate vector: %w", err)
	}

  var k = 10
	var numCandidates = 10

	res, err := client.Search().
		Index("vector-search-rodents").
		Knn(types.KnnSearch{
      # Field in document containing vector
			Field:         "text_embedding.predicted_value",
      # Number of neighbors to return
			K:             &amp;k,
      # Number of candidates to evaluate in comparison
			NumCandidates: &amp;numCandidates,
      # Query vector returned from Hugging Face inference API
			QueryVector:   vector,
		}).
		Do(context.Background())

	if err != nil {
		return nil, err
	}

	return getRodents(res.Hits.Hits)
}
<p>Cabe señalar que las opciones de <code>K</code> y <code>NumCandidates</code> siguen siendo las mismas independientemente de las dos opciones y que se generan los mismos resultados, ya que estamos usando el mismo modelo para generar las incrustaciones</p><h2>Conclusión</h2><p>Aquí discutimos cómo realizar búsqueda vectorial en Elasticsearch usando el <a href="https://www.elastic.co/guide/en/elasticsearch/client/go-api/current/index.html">cliente Elasticsearch</a> Go. Echa un vistazo al <a href="https://github.com/carlyrichmond/gopher-hunting-elasticsearch">repositorio de GitHub</a> para ver todo el código de este serial. Sigue la <a href="https://www.elastic.co/search-labs/blog/hybrid-search-with-the-elasticsearch-go-client">parte 3</a> para obtener una visión general de cómo combinar la búsqueda vectorial con las capacidades de búsqueda por palabras clave que se tratan en <a href="https://www.elastic.co/search-labs/blog/perform-text-queries-with-the-elasticsearch-go-client">la primera parte</a> de Go.</p><p>Hasta entonces, ¡feliz caza de topos!</p><h2>Recursos</h2><ol><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html">Guía Elasticsearch</a></p></li><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/client/go-api/current/index.html">Cliente Elasticsearch Go</a></p></li><li><p><a href="https://www.elastic.co/what-is/vector-search">¿Qué es la búsqueda vectorial? | Elástico</a></p></li></ol>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/perform-vector-search-with-the-elasticsearch-go-client</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/perform-vector-search-with-the-elasticsearch-go-client</guid>
    <category><![CDATA[Base de datos vectorial]]></category>
    <category><![CDATA[Go]]></category>
    <dc:creator><![CDATA[Carly Richmond,Laurent Saint-Félix]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdcae959696d55a9b/6a1704d5ab7f085a56db9d7c/491ef9efbb30b253e1d9e3b7f816a9a23c8f5264-721x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Wed, 01 Nov 2023 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Realiza consultas de texto con el cliente Elasticsearch Go]]></title>
    <description><![CDATA[Aprende a realizar consultas de texto tradicionales en Elasticsearch usando el cliente Elasticsearch Go a través de un ejemplo práctico.]]></description>
    <content:encoded><![CDATA[<p>Desarrollar software en cualquier lenguaje de programación, incluido Go, es comprometer con una vida entera de aprendizaje. A lo largo de su carrera universitaria y profesional, Carly tuvo que adaptar a ser políglota y experimentar con muchos lenguajes de programación, incluyendo Python, C, JavaScript, TypeScript y Java. ¡Pero eso no fue suficiente! ¡Hace poco también empezó a jugar con Go!</p><p>Al igual que los animales, los lenguajes de programación y uno de tus autores amables, la búsqueda experimentó una evolución de diferentes prácticas que pueden ser difíciles de elegir para tu propio caso de uso. En este blog, compartiremos una visión general de la búsqueda tradicional por palabras clave junto <a href="https://github.com/carlyrichmond/gopher-hunting-elasticsearch">con un ejemplo</a> usando <a href="https://www.elastic.co/elasticsearch/">Elasticsearch</a> y el <a href="https://www.elastic.co/guide/en/elasticsearch/client/go-api/current/index.html">cliente Elasticsearch Go</a>.</p><h2>Prerrequisitos</h2><p>Para seguir con este ejemplo, cerciorar de cumplir los siguientes requisitos:</p><ol><li><p>Instalación de Go versión 1.21 o posterior</p></li><li><p>Crea tu propio repositorio de Go usando la estructura recomendada y la gestión de paquetes que se menciona en la <a href="https://go.dev/doc/code">documentación de Go</a></p></li><li><p>Creación de tu propio clúster Elasticsearch, poblado con un conjunto de <a href="https://github.com/carlyrichmond/gopher-hunting-elasticsearch#sources">páginas basadas en roedores</a> , incluyendo para nuestro amable <a href="https://en.wikipedia.org/wiki/Gopher">Gopher</a>, de Wikipedia:</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6a436c42996e5172/6a1704cf0c48573d1c01a957/34fa81a9b4c292634c719b8303a9b6b7506d7920-1440x662.png" alt="Página de Wikipedia sobre los Topos" /><h2>Conexión con Elasticsearch</h2><p>En nuestros ejemplos, emplearemos la <a href="https://www.elastic.co/guide/en/elasticsearch/client/go-api/current/typedapi.html">API tipada</a> que ofrece el cliente Go. Establecer una conexión segura para cualquier consulta requiere configurar el cliente usando cualquiera de:</p><ol><li><p>Cloud ID y clave API si se emplea Elastic Cloud.</p></li><li><p>URL del clúster, nombre de usuario, contraseña y el certificado.</p></li></ol><p>Conectarse a nuestro clúster ubicado en Elastic Cloud sería así:</p>func GetElasticsearchClient() (*elasticsearch.TypedClient, error) {
	var cloudID = os.Getenv("ELASTIC_CLOUD_ID")
	var apiKey = os.Getenv("ELASTIC_API_KEY")

	var es, err = elasticsearch.NewTypedClient(elasticsearch.Config{
		CloudID: cloudID,
		APIKey:  apiKey,
		Logger:  &amp;elastictransport.ColorLogger{os.Stdout, true, true},
	})

	if err != nil {
		return nil, fmt.Errorf("unable to connect: %w", err)
	}

	return es, nil
}
<p>La conexión <code>client</code> puede usar entonces para buscar, como se muestra más adelante.</p><h2>Búsqueda por palabras clave</h2><p>La búsqueda por palabras clave es el tipo de búsqueda fundamental con el que estamos familiarizados desde la creación de <a href="https://en.wikipedia.org/wiki/Archie_(search_engine)">Archie</a>, el primer motor de búsqueda documentado en Internet escrito en 1990.</p><p>Un componente central de la búsqueda por palabras clave es la traducción de documentos a un índice invertido. Exactamente como el índice que se encuentra al final de un libro de texto, un índice invertido contiene un mapeo entre una lista de tokens y su ubicación en cada documento. El siguiente diagrama muestra las etapas clave para generar el índice:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt366681a12027f14b/6a17e7aa1d1b831c2093e452/9cd7b2a60d9aa54facb37738b821bba6ca925830-1440x581.png" alt="Generación de índice invertido" /><p>Como se muestra arriba, la generación de tokens en Elasticsearch comprende tres etapas clave:</p><ol><li><p>Despojar personajes innecesarios mediante cero o más <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-charfilters.html"><code>char_filters</code></a>. En nuestro ejemplo, eliminamos elementos HTML dentro del campo <code>body_content</code> mediante el filtro <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-htmlstrip-charfilter.html"><code>html_strip</code></a> .</p></li><li><p>Separar los tokens del contenido con el<a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-tokenizers.html"> tokenizador</a> <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-tokenizers.html"><code>standard</code></a>, que se divide por espaciado y puntaje clave.</p></li><li><p>Eliminar tokens no deseados o transformar tokens del flujo de salida del tokenizador usando opciones de cero o más <code>filter</code>, como el<a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-lowercase-tokenfilter.html"> filtro de token</a> <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-lowercase-tokenfilter.html"><code>lowercase</code></a>o stemmers como el<a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-snowball-tokenfilter.html"> stemmer</a> <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-snowball-tokenfilter.html"><code>snowball</code></a>para transformar tokens de nuevo a su raíz de lenguaje.</p></li></ol><h2>Búsqueda en Elasticsearch con Go</h2><p>Al consultar con el cliente Go, especificamos el índice que queremos buscar y pasar en la consulta y otras opciones, igual que en el siguiente ejemplo:</p>func KeywordSearch(client *elasticsearch.TypedClient, term string) ([]Rodent, error) {
	res, err := client.Search().
		Index("search-rodents").
		Query(&amp;types.Query{
			Match: map[string]types.MatchQuery{
				"title": {Query: term},
			},
		}).
		From(0).
		Size(10).
		Do(context.Background())

	if err != nil {
		return nil, fmt.Errorf("could not search for rodents: %w", err)
	}

	return getRodents(res.Hits.Hits)
}
<p>En el ejemplo anterior, realizamos una<a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html"> consulta</a> estándar de <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html"><code>match</code></a>para encontrar cualquier documento en nuestro índice que contenga la cadena especificada que se pasó a nuestra función. Observar que pasamos un <a href="https://pkg.go.dev/context#Background">nuevo contexto vacío</a> a la ejecución de búsqueda mediante <code>Do(context.Background())</code>. Además, cualquier error devuelto por Elasticsearch se envía al atributo <code>err</code> para el registro y el manejo de errores.</p><p>Los resultados se devuelven en <code>res.Hits.Hits</code> con el atributo <code>_Source</code> que contiene el documento en formato JSON. Para convertir esta fuente a un struct compatible con Go, necesitamos <a href="https://pkg.go.dev/encoding/json#Unmarshal">deshacer el marshal</a> de la respuesta JSON usando el <a href="https://pkg.go.dev/encoding/json">paquete de codificación/json</a> de Go, como se muestra en el siguiente ejemplo:</p>func getRodents(hits []types.Hit) ([]Rodent, error) {
	var rodents []Rodent

	for _, hit := range hits {
		var currentRodent Rodent
		err := json.Unmarshal(hit.Source_, &amp;currentRodent)

		if err != nil {
			return nil, fmt.Errorf("an error occurred while unmarshaling rodent %s: %w", hit.Id_, err)
		}

		currentRodent.ID = hit.Id_
		rodents = append(rodents, currentRodent)
	}

	return rodents, nil
}
<p>Buscar y desorganizar la consulta <code>gopher</code> devolverá la página de Wikipedia de Gopher como se esperaba:</p>[
  {ID:64f74ecd4acb3df024d91112 Title:Gopher - Wikipedia Url:https://en.wikipedia.org/wiki/Gopher}
]
<p>Sin embargo, si preguntamos <code>What do Gophers eat?</code> no obtenemos exactamente los resultados que queremos:</p>[]
<p>Una búsqueda sencilla por palabra clave permite que los resultados devuelvan a tu aplicación Go de forma eficiente que funciona de una manera que conocemos por las aplicaciones que empleamos. También funciona muy bien para coincidencias de términos exactos relevantes para escenarios como buscar una compañía o término concreto.</p><p>Sin embargo, como vimos arriba, le cuesta identificar el contexto y la semántica debido al problema de la desadaptación del vocabulario. Además, el soporte para formatos de archivo no textuales, como imágenes y audio, resulta complicado.</p><h2>Conclusión</h2><p>Aquí hablamos de cómo realizar consultas de texto tradicionales en Elasticsearch usando el <a href="https://www.elastic.co/guide/en/elasticsearch/client/go-api/current/index.html">cliente Elasticsearch</a> Go. Dado que Go se usa ampliamente para scripting de infraestructura y construcción de servidores sitio web, es útil saber cómo buscar en Go.</p><p>Echa un vistazo al <a href="https://www.elastic.co/search-labs/blog/perform-vector-search-with-the-elasticsearch-go-client">repositorio de GitHub</a> para ver todo el código de este serial. Continúa la <a href="https://www.elastic.co/search-labs/blog/perform-vector-search-with-the-elasticsearch-go-client">parte 2</a> para obtener una visión general de la búsqueda vectorial y cómo realizar la búsqueda vectorial en Go. Hasta entonces, ¡feliz caza de topos!</p><h2>Recursos</h2><ol><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html">Guía Elasticsearch</a></p></li><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/client/go-api/current/index.html">Cliente Elasticsearch Go</a></p></li><li><p><a href="https://codingexplained.com/coding/elasticsearch/understanding-analysis-in-elasticsearch-analyzers">Comprendiendo el análisis en Elasticsearch (analizadores) por Bo Andersen | #CodingExplained</a></p></li></ol>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/perform-text-queries-with-the-elasticsearch-go-client</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/perform-text-queries-with-the-elasticsearch-go-client</guid>
    <category><![CDATA[Go]]></category>
    <dc:creator><![CDATA[Carly Richmond,Laurent Saint-Félix]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdcae959696d55a9b/6a1704d5ab7f085a56db9d7c/491ef9efbb30b253e1d9e3b7f816a9a23c8f5264-721x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 31 Oct 2023 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>