Indexing Attachments for Vector Search



Overview

Attachments in RavenDB


  • Attachments in RavenDB allow you to associate binary files with your JSON documents.
    You can use attachments to store images, PDFs, videos, text files, or any other format.

  • Attachments are stored separately from documents, reducing document size and avoiding unnecessary duplication. They are stored as binary data, regardless of content type.

  • Attachments are handled as streams, allowing efficient upload and retrieval.
    Learn more in: What are attachments.


You can index attachment content in a vector field within a static-index,
enabling vector search on text or numerical data that is stored in the attachments:

  • Attachments with TEXT:

    • During indexing, RavenDB processes the text into a single embedding per attachment using the built-in
      bge-micro-v2 model.
  • Attachments with NUMERICAL data:

    • While attachments can store any file type, RavenDB does Not generate embeddings from images, videos, or other non-textual content.
      Each attachment must contain a single precomputed embedding vector, generated externally.
    • RavenDB indexes the embedding vector from the attachment in and can apply quantization (e.g., index it in Int8 format) if this is configured.
    • All embeddings indexed within the same vector-field in the static-index must be vectors of the same dimension to ensure consistency in indexing and search. They must also be created using the same model.

Indexing TEXT attachments

  • The following index defines a vector field named VectorFromAttachment.

  • It indexes embeddings generated from the text content of the description.txt attachment.
    This applies to all Company documents that contain an attachment with that name.

public class Companies_ByVector_FromTextAttachment :
    AbstractIndexCreationTask<Company, Companies_ByVector_FromTextAttachment.IndexEntry>
{
    public class IndexEntry()
    {
        // This index-field will hold embeddings
        // generated from the TEXT in the attachments.
        public object VectorFromAttachment { get; set; }
    }

    public Companies_ByVector_FromTextAttachment()
    {
        Map = companies => from company in companies
            
            // Load the attachment from the document (ensure it is not null)
            let attachment = LoadAttachment(company, "description.txt")
            where attachment != null
            
            select new IndexEntry()
            {
                // Index the text content from the attachment in the vector field
                VectorFromAttachment =
                    CreateVector(attachment.GetContentAsString(Encoding.UTF8))
            };

        // Configure the vector field:
        VectorIndexes.Add(x => x.VectorFromAttachment,
            new VectorOptions()
            {
                // Specify 'Text' as the source format
                SourceEmbeddingType = VectorEmbeddingType.Text,
                // Specify the desired destination format within the index
                DestinationEmbeddingType = VectorEmbeddingType.Single
            });
    
        SearchEngineType = Raven.Client.Documents.Indexes.SearchEngineType.Corax;
    }
}
public class Companies_ByVector_FromTextAttachment_JS :
    AbstractJavaScriptIndexCreationTask
{
    public Companies_ByVector_FromTextAttachment_JS()
    {
        Maps = new HashSet<string>
        {
            $@"map('Companies', function (company) {{

                   var attachment = loadAttachment(company, 'description.txt');
                   if (!attachment) return null;
 
                   return {{
                       VectorFromAttachment: createVector(attachment.getContentAsString('utf8'))
                   }};
            }})"
        };

        Fields = new Dictionary<string, IndexFieldOptions>()
        {
            {
                "VectorFromAttachment",
                new IndexFieldOptions()
                {
                    Vector = new()
                    {
                        SourceEmbeddingType = VectorEmbeddingType.Text,
                        DestinationEmbeddingType = VectorEmbeddingType.Single
                    }
                }
            }
        };
    
        SearchEngineType = Raven.Client.Documents.Indexes.SearchEngineType.Corax;
    }
}
var indexDefinition = new IndexDefinition
{
    Name = "Companies/ByVector/FromTextAttachment",
    
    Maps = new HashSet<string>
    {
        @"from company in docs.Companies

          let attachment = LoadAttachment(company, ""description.txt"")
          where attachment != null

          select new 
          {
              VectorFromAttachment =
                  CreateVector(attachment.GetContentAsString(Encoding.UTF8))
          }"
    },
    
    Fields = new Dictionary<string, IndexFieldOptions>()
    {
        {
            "VectorFromAttachment",
            new IndexFieldOptions()
            {
                Vector = new VectorOptions()
                {
                    SourceEmbeddingType = VectorEmbeddingType.Text,
                    DestinationEmbeddingType = VectorEmbeddingType.Single
                }
            }
        }
    },
    
    Configuration = new IndexConfiguration()
    {
        ["Indexing.Static.SearchEngineType"] = "Corax"
    }
};

store.Maintenance.Send(new PutIndexesOperation(indexDefinition));
// Prepare text as `byte[]` to be stored as attachments:
// =====================================================
var byteArray1 = Encoding.UTF8.GetBytes(
    "Supplies soft drinks, fruit juices, and flavored syrups to restaurants and retailers.");
var byteArray2 = Encoding.UTF8.GetBytes(
    "Supplies fine dining restaurants with premium meats, cheeses, and wines across France.");
var byteArray3 = Encoding.UTF8.GetBytes(
    "An American grocery chain known for its fresh produce, organic foods, and local meats.");
var byteArray4 = Encoding.UTF8.GetBytes(
    "An Asian grocery store specializing in ingredients for Japanese and Thai cuisine.");
var byteArray5 = Encoding.UTF8.GetBytes(
    "A rural general store offering homemade jams, fresh-baked bread, and locally crafted gifts.");

using (var session = store.OpenSession())
{
    // Load existing Company documents from RavenDB's sample data:
    // ===========================================================
    var company1 = session.Load<Company>("companies/11-A");
    var company2 = session.Load<Company>("companies/26-A");
    var company3 = session.Load<Company>("companies/32-A");
    var company4 = session.Load<Company>("companies/41-A");
    var company5 = session.Load<Company>("companies/43-A");
    
    // Store the attachments in the documents (using MemoryStream):
    // ============================================================
    session.Advanced.Attachments.Store(company1, "description.txt",
        new MemoryStream(byteArray1), "text/plain");
    session.Advanced.Attachments.Store(company2, "description.txt",
        new MemoryStream(byteArray2), "text/plain");
    session.Advanced.Attachments.Store(company3, "description.txt",
        new MemoryStream(byteArray3), "text/plain");
    session.Advanced.Attachments.Store(company4, "description.txt",
        new MemoryStream(byteArray4), "text/plain");
    session.Advanced.Attachments.Store(company5, "description.txt",
        new MemoryStream(byteArray5), "text/plain");
    
    session.SaveChanges();
}

Execute a vector search using the index:
Results will include Company documents whose attachment contains text similar to "chinese food".

var relevantCompanies = session
    .Query<Companies_ByVector_FromTextAttachment.IndexEntry,
        Companies_ByVector_FromTextAttachment>()
    .VectorSearch(
        field => field
            .WithField(x => x.VectorFromAttachment),
        searchTerm => searchTerm
            .ByText("chinese food"), 0.8f)
    .Customize(x => x.WaitForNonStaleResults())
    .OfType<Company>()
    .ToList();
var relevantCompanies = await asyncSession
    .Query<Companies_ByVector_FromTextAttachment.IndexEntry,
        Companies_ByVector_FromTextAttachment>()
    .VectorSearch(
        field => field
            .WithField(x => x.VectorFromAttachment),
        searchTerm => searchTerm
            .ByText("chinese food"), 0.8f)
    .Customize(x => x.WaitForNonStaleResults())
    .OfType<Company>()
    .ToListAsync();
var relevantCompanies = session.Advanced
    .DocumentQuery<Companies_ByVector_FromTextAttachment.IndexEntry,
        Companies_ByVector_FromTextAttachment>()
    .VectorSearch(
        field => field
            .WithField(x => x.VectorFromAttachment),
        searchTerm => searchTerm
            .ByText("chinese food"), 0.8f)
    .WaitForNonStaleResults()
    .OfType<Company>()
    .ToList();
var relevantCompanies = await asyncSession.Advanced
    .AsyncDocumentQuery<Companies_ByVector_FromTextAttachment.IndexEntry,
        Companies_ByVector_FromTextAttachment>()
    .VectorSearch(
        field => field
            .WithField(x => x.VectorFromAttachment),
        searchTerm => searchTerm
            .ByText("chinese food"), 0.8f)
    .WaitForNonStaleResults()
    .OfType<Company>()
    .ToListAsync();
var relevantCompanies = session.Advanced
    .RawQuery<Company>(@"
        from index 'Companies/ByVector/FromTextAttachment'
        where vector.search(VectorFromAttachment, $searchTerm, 0.8)")
    .AddParameter("searchTerm", "chinese food")
    .WaitForNonStaleResults()
    .ToList();
var relevantCompanies = await asyncSession.Advanced
    .AsyncRawQuery<Company>(@"
        from index 'Companies/ByVector/FromTextAttachment'
        where vector.search(VectorFromAttachment, $searchTerm, 0.8)")
    .AddParameter("searchTerm", "chinese food")
    .WaitForNonStaleResults()
    .ToListAsync();
from index "Companies/ByVector/FromTextAttachment"
where vector.search(VectorFromAttachment, $searchTerm, 0.8)
{ "searchTerm" : "chinese food" }

You can now extract the text from the attachments of the resulting documents:

// Extract text from the attachment of the first resulting document
// ================================================================

// Retrieve the attachment stream
var company = relevantCompanies[0];
var attachmentResult =  session.Advanced.Attachments.Get(company, "description.txt");
var attStream = attachmentResult.Stream;
                
// Read the attachment content into memory and decode it as a UTF-8 string
var ms = new MemoryStream();
attStream.CopyTo(ms);
string attachmentText = Encoding.UTF8.GetString(ms.ToArray());

Indexing NUMERICAL attachments

LINQ index

  • The following index defines a vector field named VectorFromAttachment.

  • It indexes embeddings generated from the numerical data stored in the vector.raw attachment.
    This applies to all Company documents that contain an attachment with that name.

  • Each attachment contains raw numerical data in 32-bit floating-point format.

public class Companies_ByVector_FromNumericalAttachment :
    AbstractIndexCreationTask<Company, Companies_ByVector_FromNumericalAttachment.IndexEntry>
{
    public class IndexEntry()
    {
        // This index-field will hold embeddings
        // generated from the NUMERICAL content in the attachments.
        public object VectorFromAttachment { get; set; }
    }
    
    public Companies_ByVector_FromNumericalAttachment()
    {
        Map = companies => from company in companies
            
            // Load the attachment from the document (ensure it is not null)
            let attachment = LoadAttachment(company, "vector.raw")
            where attachment != null
            
            select new IndexEntry
            {
                // Index the attachment's content in the vector field
                VectorFromAttachment = CreateVector(attachment.GetContentAsStream())
            };

        // Configure the vector field:
        VectorIndexes.Add(x => x.VectorFromAttachment,
            new VectorOptions()
            {
                // Define the source embedding type
                SourceEmbeddingType = VectorEmbeddingType.Single,
                // Define the desired destination format within the index
                DestinationEmbeddingType = VectorEmbeddingType.Single
            });

        SearchEngineType = Raven.Client.Documents.Indexes.SearchEngineType.Corax;
    }
}
var indexDefinition = new IndexDefinition 
{
    Name = "Companies/ByVector/FromNumericalAttachment",

    Maps = new HashSet<string>
    {
        @"from company in docs.Companies

          let attachment = LoadAttachment(company, ""vector.raw"")
          where attachment != null
    
          select new
          {
              VectorFromAttachment = CreateVector(attachment.GetContentAsStream())
          }"
    },
    
    Fields = new Dictionary<string, IndexFieldOptions>()
    {
        {
            "VectorFromAttachment",
            new IndexFieldOptions()
            {
                Vector = new VectorOptions()
                {
                    SourceEmbeddingType = VectorEmbeddingType.Single,
                    DestinationEmbeddingType = VectorEmbeddingType.Single
                }
            }
        }
    },
    
    Configuration = new IndexConfiguration()
    {
        ["Indexing.Static.SearchEngineType"] = "Corax"
    }
};

store.Maintenance.Send(new PutIndexesOperation(indexDefinition));
// These vectors are simple pre-computed embedding vectors with 32-bit floating-point values.
// Note: In a real scenario, embeddings would be generated by a model.
// ==========================================================================================
var v1 = new float[] { 0.1f, 0.2f, 0.3f, 0.4f };
var v2 = new float[] { 0.1f, 0.7f, 0.8f, 0.9f };
var v3 = new float[] { 0.5f, 0.6f, 0.7f, 0.8f };

// Prepare the embedding vectors as `byte[]` to be stored as attachments:
// =====================================================================
var byteArray1 = MemoryMarshal.Cast<float, byte>(v1).ToArray();
var byteArray2 = MemoryMarshal.Cast<float, byte>(v2).ToArray();
var byteArray3 = MemoryMarshal.Cast<float, byte>(v3).ToArray();

using (var session = store.OpenSession())
{
    // Load existing Company documents from RavenDB's sample data:
    // ===========================================================
    var company1 = session.Load<Company>("companies/50-A");
    var company2 = session.Load<Company>("companies/51-A");
    var company3 = session.Load<Company>("companies/52-A");
    
    // Store the attachments in the documents (using MemoryStream):
    // ============================================================
    session.Advanced.Attachments.Store(company1, "vector.raw", new MemoryStream(byteArray1));
    session.Advanced.Attachments.Store(company2, "vector.raw", new MemoryStream(byteArray2));
    session.Advanced.Attachments.Store(company3, "vector.raw", new MemoryStream(byteArray3));
    
    session.SaveChanges();
}

Execute a vector search using the index:
Results will include Company documents whose attachment contains vectors similar to the query vector.

var similarCompanies = session
    .Query<Companies_ByVector_FromNumericalAttachment.IndexEntry,
        Companies_ByVector_FromNumericalAttachment>()
    .VectorSearch(
        field => field
            .WithField(x => x.VectorFromAttachment),
        queryVector => queryVector
            .ByEmbedding(new float[] { 0.1f, 0.2f, 0.3f, 0.4f }))
    .Customize(x => x.WaitForNonStaleResults())
    .OfType<Company>()
    .ToList();
var similarCompanies = await asyncSession
    .Query<Companies_ByVector_FromNumericalAttachment.IndexEntry,
        Companies_ByVector_FromNumericalAttachment>()
    .VectorSearch(
        field => field
            .WithField(x => x.VectorFromAttachment),
        queryVector => queryVector
            .ByEmbedding(new float[] { 0.1f, 0.2f, 0.3f, 0.4f }))
    .Customize(x => x.WaitForNonStaleResults())
    .OfType<Company>()
    .ToListAsync();
var similarCompanies = session.Advanced
    .DocumentQuery<Companies_ByVector_FromNumericalAttachment.IndexEntry,
        Companies_ByVector_FromNumericalAttachment>()
    .VectorSearch(
        field => field
            .WithField(x => x.VectorFromAttachment),
        queryVector => queryVector
            .ByEmbedding(new float[] { 0.1f, 0.2f, 0.3f, 0.4f }))
    .WaitForNonStaleResults()
    .OfType<Company>()
    .ToList();
var similarCompanies = await asyncSession.Advanced
    .AsyncDocumentQuery<Companies_ByVector_FromNumericalAttachment.IndexEntry,
        Companies_ByVector_FromNumericalAttachment>()
    .VectorSearch(
        field => field
            .WithField(x => x.VectorFromAttachment),
        queryVector => queryVector
            .ByEmbedding(new float[] { 0.1f, 0.2f, 0.3f, 0.4f }))
    .WaitForNonStaleResults()
    .OfType<Company>()
    .ToListAsync();
var similarCompanies = session.Advanced
    .RawQuery<Company>(@"
        from index 'Companies/ByVector/FromNumericalAttachment'
        where vector.search(VectorFromAttachment, $queryVector)")
    .AddParameter("queryVector", new float[] { 0.1f, 0.2f, 0.3f, 0.4f })
    .WaitForNonStaleResults()
    .ToList();
var similarCompanies = await asyncSession.Advanced
    .AsyncRawQuery<Company>(@"
        from index 'Companies/ByVector/FromNumericalAttachment'
        where vector.search(VectorFromAttachment, $queryVector)")
    .AddParameter("queryVector", new float[] { 0.1f, 0.2f, 0.3f, 0.4f })
    .WaitForNonStaleResults()
    .ToListAsync();
from index "Companies/ByVector/FromNumericalAttachment"
where vector.search(VectorFromAttachment, $queryVector)
{ "queryVector" : [0.1, 0.2, 0.3, 0.4] }

JS index

  • The following is the JavaScript index format equivalent to the LINQ index shown above.

  • The main difference is that JavaScript indexes do Not support getContentAsStream() on attachment objects:

    • Because of this, embedding vectors must be stored in attachments as Base64-encoded strings.
    • Use getContentAsString() to retrieve the attachment content as a string, as shown in this example.

public class Companies_ByVector_FromNumericalAttachment_JS :
    AbstractJavaScriptIndexCreationTask
{
    public Companies_ByVector_FromNumericalAttachment_JS()
    {
        Maps = new HashSet<string>()
        {
            $@"map('Companies', function (company) {{

                 var attachment = loadAttachment(company, 'vector_base64.raw');
                 if (!attachment) return null;

                 return {{
                     VectorFromAttachment: createVector(attachment.getContentAsString('utf8'))
                 }};
             }})"
        };
    
        Fields = new();
        Fields.Add("VectorFromAttachment", new IndexFieldOptions()
        {
            Vector = new VectorOptions()
            {
                SourceEmbeddingType = VectorEmbeddingType.Single, 
                DestinationEmbeddingType = VectorEmbeddingType.Single
            }
        });

        SearchEngineType = Raven.Client.Documents.Indexes.SearchEngineType.Corax;
    }
}
// These vectors are simple pre-computed embedding vectors with 32-bit floating-point values.
// Note: In a real scenario, embeddings would be generated by a model.
// ==========================================================================================
var v1 = new float[] { 0.1f, 0.2f, 0.3f, 0.4f };
var v2 = new float[] { 0.1f, 0.7f, 0.8f, 0.9f };
var v3 = new float[] { 0.5f, 0.6f, 0.7f, 0.8f };

// Prepare the embedding vectors as a BASE64 string to be stored as attachments:
// =============================================================================
var base64ForV1 = Convert.ToBase64String(MemoryMarshal.Cast<float, byte>(v1));
var base64ForV2 = Convert.ToBase64String(MemoryMarshal.Cast<float, byte>(v2));
var base64ForV3 = Convert.ToBase64String(MemoryMarshal.Cast<float, byte>(v3));

// Convert to byte[] for streaming:
// ================================
var byteArray1 = Encoding.UTF8.GetBytes(base64ForV1);
var byteArray2 = Encoding.UTF8.GetBytes(base64ForV2);
var byteArray3 = Encoding.UTF8.GetBytes(base64ForV3);

using (var session = store.OpenSession())
{
    // Load existing Company documents from RavenDB's sample data:
    // ===========================================================
    var company1 = session.Load<Company>("companies/60-A");
    var company2 = session.Load<Company>("companies/61-A");
    var company3 = session.Load<Company>("companies/62-A");
    
    // Store the attachments in the documents (using MemoryStream):
    // ============================================================
    session.Advanced.Attachments.Store(company1, "vector_base64.raw", new MemoryStream(byteArray1));
    session.Advanced.Attachments.Store(company2, "vector_base64.raw", new MemoryStream(byteArray2));
    session.Advanced.Attachments.Store(company3, "vector_base64.raw", new MemoryStream(byteArray3));
    
    session.SaveChanges();
}

Execute a vector search using the index:
Results will include Company documents whose attachment contains vectors similar to the query vector.

var similarCompanies = session.Advanced
    .RawQuery<Company>(@"
        from index 'Companies/ByVector/FromNumericalAttachment/JS'
        where vector.search(VectorFromAttachment, $queryVector)")
    .AddParameter("queryVector", new float[] { 0.1f, 0.2f, 0.3f, 0.4f })
    .WaitForNonStaleResults()
    .ToList();
var similarCompanies = await asyncSession.Advanced
    .AsyncRawQuery<Company>(@"
        from index 'Companies/ByVector/FromNumericalAttachment/JS'
        where vector.search(VectorFromAttachment, $queryVector)")
    .AddParameter("queryVector", new float[] { 0.1f, 0.2f, 0.3f, 0.4f })
    .WaitForNonStaleResults()
    .ToListAsync();
from index "Companies/ByVector/FromNumericalAttachment/JS"
where vector.search(VectorFromAttachment, $queryVector)
{ "queryVector" : [0.1, 0.2, 0.3, 0.4] }

Indexing ALL attachments

  • The following index defines a vector field named VectorFromAttachment.

  • It indexes embeddings generated from the numerical data stored in ALL attachments of all Company documents.

public class Companies_ByVector_AllAttachments :
    AbstractIndexCreationTask<Company, Companies_ByVector_AllAttachments.IndexEntry>
{
    public class IndexEntry()
    {
        // This index-field will hold embeddings
        // generated from the NUMERICAL content of ALL attachments.
        public object VectorFromAttachment { get; set; }
    }
    
    public Companies_ByVector_AllAttachments()
    {
        Map = companies => from company in companies
            
            // Load ALL attachments from the document
            let attachments = LoadAttachments(company)
            
            select new IndexEntry
            {
                // Index the attachments content in the vector field
                VectorFromAttachment = CreateVector(
                    attachments.Select(e => e.GetContentAsStream()))
            };

        // Configure the vector field:
        VectorIndexes.Add(x => x.VectorFromAttachment,
            new VectorOptions()
            {
                SourceEmbeddingType = VectorEmbeddingType.Single,
                DestinationEmbeddingType = VectorEmbeddingType.Single
            });

        SearchEngineType = Raven.Client.Documents.Indexes.SearchEngineType.Corax;
    }
}
var indexDefinition = new IndexDefinition 
{
    Name = "Companies/ByVector/AllAttachments",

    Maps = new HashSet<string>
    {
        @"from company in docs.Companies

          let attachments = LoadAttachments(company)
    
          select new
          {
              VectorFromAttachment =
                  CreateVector(attachments.Select(e => e.GetContentAsStream()))
          }"
    },
    
    Fields = new Dictionary<string, IndexFieldOptions>()
    {
        {
            "VectorFromAttachment",
            new IndexFieldOptions()
            {
                Vector = new VectorOptions()
                {
                    SourceEmbeddingType = VectorEmbeddingType.Single,
                    DestinationEmbeddingType = VectorEmbeddingType.Single,
                }
            }
        }
    },
    
    Configuration = new IndexConfiguration()
    {
        ["Indexing.Static.SearchEngineType"] = "Corax"
    }
};

store.Maintenance.Send(new PutIndexesOperation(indexDefinition));
// These vectors are simple pre-computed embedding vectors with 32-bit floating-point values.
// Note: In a real scenario, embeddings would be generated by a model.
// ==========================================================================================
var v1 = new float[] { 0.1f, 0.2f, 0.3f, 0.4f };
var v2 = new float[] { 0.5f, 0.6f, 0.7f, 0.8f };

var v3 = new float[] { -0.1f, 0.2f, -0.7f, -0.8f };
var v4 = new float[] { 0.3f, -0.6f, 0.9f, -0.9f };

// Prepare the embedding vectors as `byte[]` to be stored as attachments:
// =====================================================================
var byteArray1 = MemoryMarshal.Cast<float, byte>(v1).ToArray();
var byteArray2 = MemoryMarshal.Cast<float, byte>(v2).ToArray();

var byteArray3 = MemoryMarshal.Cast<float, byte>(v3).ToArray();
var byteArray4 = MemoryMarshal.Cast<float, byte>(v4).ToArray();

using (var session = store.OpenSession())
{
    // Load existing Company documents from RavenDB's sample data:
    // ===========================================================
    var company1 = session.Load<Company>("companies/70-A");
    var company2 = session.Load<Company>("companies/71-A");
    
    // Store multiple attachments in the documents (using MemoryStream):
    // =================================================================
    
    session.Advanced.Attachments.Store(company1, "vector1.raw", new MemoryStream(byteArray1));
    session.Advanced.Attachments.Store(company1, "vector2.raw", new MemoryStream(byteArray2));
    
    session.Advanced.Attachments.Store(company2, "vector1.raw", new MemoryStream(byteArray3));
    session.Advanced.Attachments.Store(company2, "vector2.raw", new MemoryStream(byteArray4));
    
    session.SaveChanges();
}

Execute a vector search using the index:
Results will include Company documents whose attachments contains vectors similar to the query vector.

var similarCompanies = session
    .Query<Companies_ByVector_AllAttachments.IndexEntry,
        Companies_ByVector_AllAttachments>()
    .VectorSearch(
        field => field
            .WithField(x => x.VectorFromAttachment),
        queryVector => queryVector
            .ByEmbedding(new float[] { -0.1f, 0.2f, -0.7f, -0.8f }))
    .Customize(x => x.WaitForNonStaleResults())
    .OfType<Company>()
    .ToList();
var similarCompanies = await asyncSession
    .Query<Companies_ByVector_AllAttachments.IndexEntry,
        Companies_ByVector_AllAttachments>()
    .VectorSearch(
        field => field
            .WithField(x => x.VectorFromAttachment),
        queryVector => queryVector
            .ByEmbedding(new float[] { -0.1f, 0.2f, -0.7f, -0.8f }))
    .Customize(x => x.WaitForNonStaleResults())
    .OfType<Company>()
    .ToListAsync();
var similarCompanies = session.Advanced
    .DocumentQuery<Companies_ByVector_AllAttachments.IndexEntry,
        Companies_ByVector_AllAttachments>()
    .VectorSearch(
        field => field
            .WithField(x => x.VectorFromAttachment),
        queryVector => queryVector
            .ByEmbedding(new float[] { -0.1f, 0.2f, -0.7f, -0.8f }))
    .WaitForNonStaleResults()
    .OfType<Company>()
    .ToList();
var similarCompanies = await asyncSession.Advanced
    .AsyncDocumentQuery<Companies_ByVector_AllAttachments.IndexEntry,
        Companies_ByVector_AllAttachments>()
    .VectorSearch(
        field => field
            .WithField(x => x.VectorFromAttachment),
        queryVector => queryVector
            .ByEmbedding(new float[] { -0.1f, 0.2f, -0.7f, -0.8f }))
    .WaitForNonStaleResults()
    .OfType<Company>()
    .ToListAsync();
var similarCompanies = session.Advanced
    .RawQuery<Company>(@"
        from index 'Companies/ByVector/AllAttachments'
        where vector.search(VectorFromAttachment, $queryVector)")
    .AddParameter("queryVector", new float[] { 0.1f, 0.2f, -0.7f, -0.8f })
    .WaitForNonStaleResults()
    .ToList();
var similarCompanies = await asyncSession.Advanced
    .AsyncRawQuery<Company>(@"
        from index 'Companies/ByVector/AllAttachments'
        where vector.search(VectorFromAttachment, $queryVector)")
    .AddParameter("queryVector", new float[] { 0.1f, 0.2f, -0.7f, -0.8f })
    .WaitForNonStaleResults()
    .ToListAsync();
from index "Companies/ByVector/AllAttachments"
where vector.search(VectorFromAttachment, $queryVector)
{ "queryVector" : [0.1, 0.2, -0.7, -0.8] }