All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.baidu.mochow.client.MochowClient Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2024 Baidu, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package com.baidu.mochow.client;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.baidu.mochow.auth.SignOptions;
import com.baidu.mochow.http.Headers;
import com.baidu.mochow.http.HttpMethodName;
import com.baidu.mochow.http.handler.HttpResponseHandler;
import com.baidu.mochow.http.handler.MochowJsonResponseHandler;
import com.baidu.mochow.http.handler.MochowMetadataResponseHandler;
import com.baidu.mochow.http.handler.MochowErrorResponseHandler;
import com.baidu.mochow.internal.InternalRequest;
import com.baidu.mochow.internal.RestartableInputStream;
import com.baidu.mochow.util.DateUtils;
import com.baidu.mochow.util.HttpUtils;
import com.baidu.mochow.util.JsonUtils;
import com.fasterxml.jackson.annotation.JsonValue;
import com.baidu.mochow.exception.MochowClientException;

import com.baidu.mochow.model.AbstractMochowRequest;
import com.baidu.mochow.model.AbstractMochowResponse;
import com.baidu.mochow.model.AddFieldRequest;
import com.baidu.mochow.model.AliasTableRequest;
import com.baidu.mochow.model.CreateDatabaseRequest;
import com.baidu.mochow.model.CreateIndexRequest;
import com.baidu.mochow.model.CreateTableRequest;
import com.baidu.mochow.model.DeleteRequest;
import com.baidu.mochow.model.DescribeIndexRequest;
import com.baidu.mochow.model.DescribeIndexResponse;
import com.baidu.mochow.model.DescribeTableRequest;
import com.baidu.mochow.model.DescribeTableResponse;
import com.baidu.mochow.model.InsertRequest;
import com.baidu.mochow.model.InsertResponse;
import com.baidu.mochow.model.ListDatabaseResponse;
import com.baidu.mochow.model.ListTableRequest;
import com.baidu.mochow.model.ListTableResponse;
import com.baidu.mochow.model.MochowConstants;
import com.baidu.mochow.model.ModifyIndexRequest;
import com.baidu.mochow.model.QueryRequest;
import com.baidu.mochow.model.QueryResponse;
import com.baidu.mochow.model.RebuildIndexRequest;
import com.baidu.mochow.model.SearchRequest;
import com.baidu.mochow.model.SearchResponse;
import com.baidu.mochow.model.SearchRowResponse;
import com.baidu.mochow.model.SelectRequest;
import com.baidu.mochow.model.SelectResponse;
import com.baidu.mochow.model.ShowTableStatsRequest;
import com.baidu.mochow.model.ShowTableStatsResponse;
import com.baidu.mochow.model.UnaliasTableRequest;
import com.baidu.mochow.model.UpdateRequest;
import com.baidu.mochow.model.UpsertRequest;
import com.baidu.mochow.model.BatchSearchRequest;
import com.baidu.mochow.model.BatchSearchResponse;
import com.baidu.mochow.model.UpsertResponse;
import com.baidu.mochow.model.SearchRequest.BM25SearchRequestInterface;
import com.baidu.mochow.model.SearchRequest.HybridSearchRequestInterface;
import com.baidu.mochow.model.SearchRequest.SearchRequestInterface;
import com.baidu.mochow.model.SearchRequest.VectorSearchRequestInterface;

/**
 * Provides the client for accessing the Baidu VDB Service.
 */
public class MochowClient extends AbstractMochowClient {

    private static final Logger LOGGER = LoggerFactory.getLogger(MochowClient.class);

    private static final String DATABASE_PREFIX = "database";
    private static final String TABLE_PREFIX = "table";
    private static final String INDEX_PREFIX = "index";
    private static final String ROW_PREFIX = "row";

    private static final String CREATE = "create";
    private static final String LIST = "list";
    private static final String DESC = "desc";
    private static final String ADD_FIELD = "addField";
    private static final String ALIAS = "alias";
    private static final String UNALIAS = "unalias";
    private static final String STATS = "stats";
    private static final String MODIFY = "modify";
    private static final String REBUILD = "rebuild";
    private static final String INSERT = "insert";
    private static final String UPSERT = "upsert";
    private static final String DELETE = "delete";
    private static final String QUERY = "query";
    private static final String SEARCH = "search";
    private static final String BATCH_SEARCH = "batchSearch";
    private static final String UPDATE = "update";
    private static final String SELECT = "select";

    private static final HttpResponseHandler[] MOCHOW_HANDLERS = new HttpResponseHandler[]{
            new MochowMetadataResponseHandler(),
            new MochowErrorResponseHandler(),
            new MochowJsonResponseHandler()
    };

    public MochowClient() {
        this(new ClientConfiguration());
    }

    public MochowClient(ClientConfiguration config) {
        super(config, MOCHOW_HANDLERS);
    }

    public void createDatabase(String databaseName) throws MochowClientException {
        CreateDatabaseRequest createDatabaseRequest = new CreateDatabaseRequest(databaseName);
        InternalRequest internalRequest = this.createRequest(createDatabaseRequest, HttpMethodName.POST, DATABASE_PREFIX);
        internalRequest.addParameter(CREATE, "");
        fillPayload(internalRequest, createDatabaseRequest);
        this.invokeHttpClient(internalRequest, AbstractMochowResponse.class);
    }

    public void dropDatabase(String databaseName) throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(
                new AbstractMochowRequest() {}, HttpMethodName.DELETE, DATABASE_PREFIX);
        internalRequest.addParameter("database", databaseName);
        this.invokeHttpClient(internalRequest, AbstractMochowResponse.class);
    }

    public ListDatabaseResponse listDatabase() throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(
                new AbstractMochowRequest() {}, HttpMethodName.POST, DATABASE_PREFIX);
        internalRequest.addParameter(LIST, "");
        return this.invokeHttpClient(internalRequest, ListDatabaseResponse.class);
    }

    public boolean hasDatabase(String databaseName) throws MochowClientException {
        ListDatabaseResponse listDatabaseResponse = this.listDatabase();
        for (String database : listDatabaseResponse.getDatabases()) {
            if (database.equals(databaseName)) {
                return true;
            }
        }
        return false;
    }

    public void createTable(CreateTableRequest request) throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, TABLE_PREFIX);
        internalRequest.addParameter(CREATE, "");
        fillPayload(internalRequest, request);
        this.invokeHttpClient(internalRequest, AbstractMochowResponse.class);
    }

    public boolean hasTable(String databaseName, String tableName) throws MochowClientException {
        if (!this.hasDatabase(databaseName)) {
            return false;
        }
        ListTableResponse listTableResponse = this.listTable(databaseName);
        for (String table : listTableResponse.getTables()) {
            if (table.equals(tableName)) {
                return true;
            }
        }
        return false;
    }

    public void dropTable(String databaseName, String tableName) throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(
                new AbstractMochowRequest() {}, HttpMethodName.DELETE, TABLE_PREFIX);
        internalRequest.addParameter("database", databaseName);
        internalRequest.addParameter("table", tableName);
        this.invokeHttpClient(internalRequest, AbstractMochowResponse.class);
    }

    public ListTableResponse listTable(String databaseName) throws MochowClientException {
        ListTableRequest listTableRequest = new ListTableRequest(databaseName);
        InternalRequest internalRequest = this.createRequest(listTableRequest, HttpMethodName.POST, TABLE_PREFIX);
        internalRequest.addParameter(LIST, "");
        fillPayload(internalRequest, listTableRequest);
        return this.invokeHttpClient(internalRequest, ListTableResponse.class);
    }

    public DescribeTableResponse describeTable(String databaseName, String tableName) throws MochowClientException {
        DescribeTableRequest request = new DescribeTableRequest(databaseName, tableName);
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, TABLE_PREFIX);
        internalRequest.addParameter(DESC, "");
        fillPayload(internalRequest, request);
        return this.invokeHttpClient(internalRequest, DescribeTableResponse.class);
    }

    public void addField(AddFieldRequest request) throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, TABLE_PREFIX);
        internalRequest.addParameter(ADD_FIELD, "");
        fillPayload(internalRequest, request);
        this.invokeHttpClient(internalRequest, AbstractMochowResponse.class);
    }

    public void aliasTable(AliasTableRequest request) throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, TABLE_PREFIX);
        internalRequest.addParameter(ALIAS, "");
        fillPayload(internalRequest, request);
        this.invokeHttpClient(internalRequest, AbstractMochowResponse.class);
    }

    public void unaliasTable(UnaliasTableRequest request) throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, TABLE_PREFIX);
        internalRequest.addParameter(UNALIAS, "");
        fillPayload(internalRequest, request);
        this.invokeHttpClient(internalRequest, AbstractMochowResponse.class);
    }

    public ShowTableStatsResponse showTableStats(String databaseName, String tableName) throws MochowClientException {
        ShowTableStatsRequest request = new ShowTableStatsRequest(databaseName, tableName);
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, TABLE_PREFIX);
        internalRequest.addParameter(STATS, "");
        fillPayload(internalRequest, request);
        return this.invokeHttpClient(internalRequest, ShowTableStatsResponse.class);
    }

    public void createIndex(CreateIndexRequest request) throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, INDEX_PREFIX);
        internalRequest.addParameter(CREATE, "");
        fillPayload(internalRequest, request);
        this.invokeHttpClient(internalRequest, AbstractMochowResponse.class);
    }

    public DescribeIndexResponse describeIndex(String databaseName, String tableName, String indexName) throws MochowClientException {
        DescribeIndexRequest request = new DescribeIndexRequest(databaseName, tableName, indexName);
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, INDEX_PREFIX);
        internalRequest.addParameter(DESC, "");
        fillPayload(internalRequest, request);
        return this.invokeHttpClient(internalRequest, DescribeIndexResponse.class);
    }

    public void modifyIndex(ModifyIndexRequest request) throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, INDEX_PREFIX);
        internalRequest.addParameter(MODIFY, "");
        fillPayload(internalRequest, request);
        this.invokeHttpClient(internalRequest, AbstractMochowResponse.class);
    }

    public void dropIndex(String databaseName, String tableName, String indexName) throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(
            new AbstractMochowRequest() {}, HttpMethodName.DELETE, INDEX_PREFIX);
        internalRequest.addParameter("database", databaseName);
        internalRequest.addParameter("table", tableName);
        internalRequest.addParameter("indexName", indexName);
        this.invokeHttpClient(internalRequest, AbstractMochowResponse.class);
    }

    public void rebuildIndex(String databaseName, String tableName, String indexName) throws MochowClientException {
        RebuildIndexRequest request = new RebuildIndexRequest(databaseName, tableName, indexName);
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, INDEX_PREFIX);
        internalRequest.addParameter(REBUILD, "");
        fillPayload(internalRequest, request);
        this.invokeHttpClient(internalRequest, AbstractMochowResponse.class);
    }

    public InsertResponse insert(InsertRequest request) throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, ROW_PREFIX);
        internalRequest.addParameter(INSERT, "");
        fillPayload(internalRequest, request);
        return this.invokeHttpClient(internalRequest, InsertResponse.class);
    }

    public UpsertResponse upsert(UpsertRequest request) throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, ROW_PREFIX);
        internalRequest.addParameter(UPSERT, "");
        fillPayload(internalRequest, request);
        return this.invokeHttpClient(internalRequest, UpsertResponse.class);
    }

    public void delete(DeleteRequest request) throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, ROW_PREFIX);
        internalRequest.addParameter(DELETE, "");
        fillPayload(internalRequest, request);
        this.invokeHttpClient(internalRequest, AbstractMochowResponse.class);
    }

    public QueryResponse query(QueryRequest request) throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, ROW_PREFIX);
        internalRequest.addParameter(QUERY, "");
        fillPayload(internalRequest, request);
        return this.invokeHttpClient(internalRequest, QueryResponse.class);
    }

    public SearchRowResponse vectorSearch(String databaseName,
                                       String tableName,
                                       VectorSearchRequestInterface request) throws MochowClientException {
        return search(databaseName, tableName, request);
    }

    public SearchRowResponse bm25Search(String databaseName,
                                     String tableName,
                                     BM25SearchRequestInterface request) throws MochowClientException {
        return search(databaseName, tableName, request);
    }

    public SearchRowResponse hybridSearch(String databaseName,
                                       String tableName,
                                       HybridSearchRequestInterface request) throws MochowClientException {
        return search(databaseName, tableName, request);
    }

    private SearchRowResponse search(String databaseName, String tableName, SearchRequestInterface searchRequest) {
        class Request extends AbstractMochowRequest {
            public Request(Map fields) {
                this.fields = fields;
            }

            @JsonValue
            public Map toMap() {
                return this.fields;
            }

            private Map fields;
        }

        Map fields = searchRequest.toMap();
        fields.put("database", databaseName);
        fields.put("table", tableName);

        Request request = new Request(fields);

        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, ROW_PREFIX);
        internalRequest.addParameter(searchRequest.requestType(), "");
        fillPayload(internalRequest, request);
        return this.invokeHttpClient(internalRequest, SearchRowResponse.class);
    }

    /**
     * Deprecated: Use {@link #vectorSearch} instead. */
    public SearchResponse search(SearchRequest request) throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, ROW_PREFIX);
        internalRequest.addParameter(SEARCH, "");
        fillPayload(internalRequest, request);
        return this.invokeHttpClient(internalRequest, SearchResponse.class);
    }

    /**
     * * Deprecated: Use {@link #vectorSearch} instead.*/
    public BatchSearchResponse batchSearch(BatchSearchRequest request) throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, ROW_PREFIX);
        internalRequest.addParameter(BATCH_SEARCH, "");
        fillPayload(internalRequest, request);
        return this.invokeHttpClient(internalRequest, BatchSearchResponse.class);
    }

    public void update(UpdateRequest request) throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, ROW_PREFIX);
        internalRequest.addParameter(UPDATE, "");
        fillPayload(internalRequest, request);
        this.invokeHttpClient(internalRequest, AbstractMochowResponse.class);
    }

    public SelectResponse select(SelectRequest request) throws MochowClientException {
        InternalRequest internalRequest = this.createRequest(request, HttpMethodName.POST, ROW_PREFIX);
        internalRequest.addParameter(SELECT, "");
        fillPayload(internalRequest, request);
        return this.invokeHttpClient(internalRequest, SelectResponse.class);
    }

    /**
     * Creates and initializes a new request object for the specified resource.
     *
     * @param bceRequest The original BCE request created by the user.
     * @param httpMethod The HTTP method to use when sending the request.
     * @param pathVariables The optional variables used in the URI path.
     * @return A new request object populated with endpoint, resource path and specific parameters to send.
     */
    protected InternalRequest createRequest(AbstractMochowRequest bceRequest,
                                            HttpMethodName httpMethod,
                                            String...pathVariables) {
        List pathComponents = new ArrayList();
        pathComponents.add(URL_PREFIX);
        if (pathVariables != null) {
            pathComponents.addAll(Arrays.asList(pathVariables));
        }
        InternalRequest request = new InternalRequest(httpMethod, HttpUtils.appendUri(this.getEndpoint(),
                pathComponents.toArray(new String[pathComponents.size()])));

        // add header
        request.addHeader(Headers.CONTENT_TYPE, MochowConstants.CONTENT_TYPE_JSON);
        request.addHeader(Headers.DATE, DateUtils.formatAlternateIso8601Date(new Date()));

        SignOptions signOptions = new SignOptions();
        request.setSignOptions(signOptions);
        return request;
    }

    /**
     * The method to fill the internalRequest's content field with mochowRequest.
     *
     * @param internalRequest A request object, populated with endpoint, resource path, ready for callers to populate
     *                        any additional headers or parameters, and execute.
     * @param mochowRequest   The original request, as created by the user.
     */
    private void fillPayload(InternalRequest internalRequest, AbstractMochowRequest mochowRequest) {
        byte[] content = toJson(mochowRequest);
        internalRequest.addHeader(Headers.CONTENT_LENGTH, String.valueOf(content.length));
        internalRequest.addHeader(Headers.CONTENT_TYPE, DEFAULT_CONTENT_TYPE);
        internalRequest.setContent(RestartableInputStream.wrap(content));
    }

    private byte[] toJson(AbstractMochowRequest bceRequest) {
        try {
            String jsonStr = JsonUtils.toJsonString(bceRequest);
            return jsonStr.getBytes(DEFAULT_ENCODING);
        } catch (UnsupportedEncodingException e) {
            throw new MochowClientException("Fail to get UTF-8 bytes", e);
        } catch (IllegalStateException e) {
            throw new MochowClientException("Fail to convert request to json", e);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy