class Builder {

        private VearchConfig vearchConfig;
        private String baseUrl;
        private Duration timeout;
        private Boolean normalizeEmbeddings;

        public Builder vearchConfig(VearchConfig vearchConfig) {
            this.vearchConfig = vearchConfig;
            return this;
        }

        public Builder baseUrl(String baseUrl) {
            this.baseUrl = baseUrl;
            return this;
        }

        public Builder timeout(Duration timeout) {
            this.timeout = timeout;
            return this;
        }

        /**
         * Set whether to normalize embedding when add to embedding store
         *
         * @param normalizeEmbeddings whether to normalize embedding when add to embedding store
         * @return builder
         */
        public Builder normalizeEmbeddings(Boolean normalizeEmbeddings) {
            this.normalizeEmbeddings = normalizeEmbeddings;
            return this;
        }

        public VearchEmbeddingStore build() {
            return new VearchEmbeddingStore(baseUrl, timeout, vearchConfig, normalizeEmbeddings);
        }
    }

    @Override
    public String add(Embedding embedding) {
        String id = randomUUID();
        add(id, embedding);
        return id;
    }

    @Override
    public void add(String id, Embedding embedding) {
        addInternal(id, embedding, null);
    }

    @Override
    public String add(Embedding embedding, TextSegment textSegment) {
        String id = randomUUID();
        addInternal(id, embedding, textSegment);
        return id;
    }

    @Override
    public List<String> addAll(List<Embedding> embeddings) {
        List<String> ids = embeddings.stream()
                .map(ignored -> randomUUID())
                .collect(toList());
        addAllInternal(ids, embeddings, null);
        return ids;
    }

    @Override
    public List<String> addAll(List<Embedding> embeddings, List<TextSegment> embedded) {
        List<String> ids = embeddings.stream()
                .map(ignored -> randomUUID())
                .collect(toList());
        addAllInternal(ids, embeddings, embedded);
        return ids;
    }

    @Override
    public List<EmbeddingMatch<TextSegment>> findRelevant(Embedding referenceEmbedding, int maxResults, double minScore) {
        double minSimilarity = CosineSimilarity.fromRelevanceScore(minScore);
        List<String> fields = new ArrayList<>(Arrays.asList(vearchConfig.getTextFieldName(), vearchConfig.getEmbeddingFieldName()));
        fields.addAll(vearchConfig.getMetadataFieldNames());
        SearchRequest request = SearchRequest.builder()
                .query(SearchRequest.QueryParam.builder()
                        .sum(singletonList(SearchRequest.VectorParam.builder()
                                .field(vearchConfig.getEmbeddingFieldName())
                                .feature(referenceEmbedding.vectorAsList())
                                .minScore(minSimilarity)
                                .build()))
                        .build())
                .size(maxResults)
                .fields(fields)
                .build();

        SearchResponse response = vearchClient.search(vearchConfig.getDatabaseName(), vearchConfig.getSpaceName(), request);
        return toEmbeddingMatch(response.getHits());
    }

    public void deleteSpace() {
        vearchClient.deleteSpace(vearchConfig.getDatabaseName(), vearchConfig.getSpaceName());
    }

    private void addInternal(String id, Embedding embedding, TextSegment embedded) {
        addAllInternal(singletonList(id), singletonList(embedding), embedded == null ? null : singletonList(embedded));
    }

    private void addAllInternal(List<String> ids, List<Embedding> embeddings, List<TextSegment> embedded) {<FILL_FUNCTION_BODY>

        ids = ensureNotEmpty(ids, "ids");
        embeddings = ensureNotEmpty(embeddings, "embeddings");
        ensureTrue(ids.size() == embeddings.size(), "ids size is not equal to embeddings size");
        ensureTrue(embedded == null || embeddings.size() == embedded.size(), "embeddings size is not equal to embedded size");

        List<Map<String, Object>> documents = new ArrayList<>(ids.size());
        for (int i = 0; i < ids.size(); i++) {
            Map<String, Object> document = new HashMap<>(4);
            document.put("_id", ids.get(i));
            Map<String, List<Float>> embeddingValue = new HashMap<>(1);
            Embedding embedding = embeddings.get(i);
            if (normalizeEmbeddings) {
                embedding.normalize();
            }
            embeddingValue.put("feature", embedding.vectorAsList());
            document.put(vearchConfig.getEmbeddingFieldName(), embeddingValue);
            if (embedded != null) {
                document.put(vearchConfig.getTextFieldName(), embedded.get(i).text());
                Map<String, String> metadata = embedded.get(i).metadata().asMap();
                for (String metadataFieldName : vearchConfig.getMetadataFieldNames()) {
                    metadata.putIfAbsent(metadataFieldName, "");
                }
                document.putAll(metadata);
            } else {
                // vearch do not allow nullable value
                document.put(vearchConfig.getTextFieldName(), "");
                if (!isNullOrEmpty(vearchConfig.getMetadataFieldNames())) {
                    for (String metadataFieldName : vearchConfig.getMetadataFieldNames()) {
                        document.put(metadataFieldName, "");
                    }
                }
            }
            documents.add(document);
        }
        BulkRequest request = BulkRequest.builder()
                .documents(documents)
                .build();
        vearchClient.bulk(vearchConfig.getDatabaseName(), vearchConfig.getSpaceName(), request);
    
<no_super_class>