﻿---
title: Dense vectors and kNN search
description: When working with vector embeddings for semantic search or machine learning applications, the Go client provides support for dense vector indexing and...
url: https://www.elastic.co/elastic/docs-builder/docs/3016/reference/elasticsearch/clients/go/using-the-api/dense-vectors
products:
  - Elasticsearch
  - Elasticsearch Client
  - Elasticsearch Go Client
---

# Dense vectors and kNN search
<applies-to>
  - Elastic Stack: Generally available since 9.3
</applies-to>

When working with vector embeddings for semantic search or machine learning applications, the Go client provides support for dense vector indexing and k-nearest neighbors (kNN) search. For the full kNN search reference, see [kNN search](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/3016/solutions/search/vector/knn) in the Elasticsearch documentation.

## Creating an index with dense vector mapping

Before indexing documents with vectors, create an index with the appropriate dense vector mapping.
<tab-set>
  <tab-item title="Low-level API">
    ```go
    mapping := `{
      "mappings": {
        "properties": {
          "docid":  { "type": "keyword" },
          "title":  { "type": "text" },
          "emb": {
            "type": "dense_vector",
            "dims": 1536,
            "index": true,
            "similarity": "cosine"
          }
        }
      }
    }`

    res, err := client.Indices.Create(
        "my-vectors",
        client.Indices.Create.WithBody(strings.NewReader(mapping)),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer res.Body.Close()
    ```
  </tab-item>

  <tab-item title="Fully-typed API">
    ```go
    similarity := densevectorsimilarity.Cosine

    res, err := es.Indices.
        Create("my-vectors").
        Request(&create.Request{
            Mappings: &types.TypeMapping{
                Properties: map[string]types.Property{
                    "docid": types.NewKeywordProperty(),
                    "title": types.NewTextProperty(),
                    "emb": types.DenseVectorProperty{
                        Dims:       some.Int(1536),
                        Index:      some.Bool(true),
                        Similarity: &similarity,
                    },
                },
            },
        }).
        Do(context.Background())
    ```
  </tab-item>

  <tab-item title="esdsl API">
    The [`esdsl`](https://www.elastic.co/elastic/docs-builder/docs/3016/reference/elasticsearch/clients/go/typed-api/esdsl) mapping builders provide a concise, fluent syntax:
    ```go
    import "github.com/elastic/go-elasticsearch/v9/typedapi/esdsl"
    ```

    ```go
    mappings := esdsl.NewTypeMapping().
        AddProperty("docid", esdsl.NewKeywordProperty()).
        AddProperty("title", esdsl.NewTextProperty()).
        AddProperty("emb", esdsl.NewDenseVectorProperty().
            Dims(1536).
            Index(true).
            Similarity(densevectorsimilarity.Cosine))

    res, err := es.Indices.
        Create("my-vectors").
        Mappings(mappings).
        Do(context.Background())
    ```
  </tab-item>
</tab-set>


## Indexing documents with vectors

<tab-set>
  <tab-item title="Low-level API">
    ```go
    doc := `{
        "docid": "doc1",
        "title": "Example document with vector embedding",
        "emb": [0.1, 0.2, 0.3, 0.4, 0.5]
    }`

    res, err := client.Index(
        "my-vectors",
        strings.NewReader(doc),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer res.Body.Close()
    ```
  </tab-item>

  <tab-item title="Fully-typed API">
    The `types.DenseVectorF32` type automatically encodes `[]float32` vectors as base64 strings during JSON serialization, reducing payload size and improving indexing speed:
    ```go
    type Document struct {
        DocID string               `json:"docid"`
        Title string               `json:"title"`
        Emb   types.DenseVectorF32 `json:"emb"`
    }

    document := Document{
        DocID: "doc1",
        Title: "Example document with vector embedding",
        Emb:   types.DenseVectorF32{0.1, 0.2, 0.3, 0.4, 0.5},
    }

    res, err := es.Index("my-vectors").
        Request(document).
        Do(context.Background())
    ```
  </tab-item>
</tab-set>


## Searching with kNN

Once your vectors are indexed, you can perform k-nearest neighbors (kNN) search to find similar documents:
<tab-set>
  <tab-item title="Low-level API">
    ```go
    query := `{
      "query": {
        "knn": {
          "field": "emb",
          "query_vector": [0.1, 0.2, 0.3, 0.4, 0.5],
          "k": 10,
          "num_candidates": 100
        }
      }
    }`

    res, err := client.Search(
        client.Search.WithIndex("my-vectors"),
        client.Search.WithBody(strings.NewReader(query)),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer res.Body.Close()
    ```
  </tab-item>

  <tab-item title="Fully-typed API">
    ```go
    queryVector := []float32{0.1, 0.2, 0.3, 0.4, 0.5}
    k := 10
    numCandidates := 100

    res, err := es.Search().
        Index("my-vectors").
        Request(&search.Request{
            Query: &types.Query{
                Knn: &types.KnnQuery{
                    Field:         "emb",
                    QueryVector:   queryVector,
                    K:             &k,
                    NumCandidates: &numCandidates,
                },
            },
        }).
        Do(context.Background())
    ```
  </tab-item>

  <tab-item title="esdsl API">
    The [`esdsl`](https://www.elastic.co/elastic/docs-builder/docs/3016/reference/elasticsearch/clients/go/typed-api/esdsl) query builders provide a fluent syntax for kNN search:
    ```go
    queryVector := []float32{0.1, 0.2, 0.3, 0.4, 0.5}

    res, err := es.Search().
        Index("my-vectors").
        Query(
            esdsl.NewKnnQuery().
                Field("emb").
                QueryVector(queryVector...).
                K(10).
                NumCandidates(100),
        ).
        Do(context.Background())
    ```
  </tab-item>
</tab-set>


## Performance benefits

Using `types.DenseVectorF32` (typed API) provides significant performance improvements over standard JSON arrays of floats:
- **Reduced payload size**: base64 encoding is more compact than JSON number arrays
- **Faster parsing**: Eliminates JSON number parsing overhead
- **Improved indexing speed**: Performance gains increase with vector dimensionality and can improve indexing speeds by up to 3x

<note>
  For best performance, use `types.DenseVectorF32` when your vectors are already in `[]float32` format. If you have pre-encoded bytes, use `types.DenseVectorBytes` to avoid re-encoding.
</note>


## Using DenseVectorBytes

If you already have pre-encoded vector bytes from another system, use `types.DenseVectorBytes`:
```go
type Document struct {
    Emb types.DenseVectorBytes `json:"emb"`
}

vectorBytes := []byte{...}
document := Document{
    Emb: types.DenseVectorBytes(vectorBytes),
}

res, err := es.Index("my-vectors").
    Request(document).
    Do(context.Background())
```