async search(request) {
    const { from, size, scrollTTL, searchBody } = request.getSearchParams();
    const index = request.getIndex({ required: false });
    const collection = request.getCollection({ required: false });
    const targets = request.getArray("targets", []);
    const lang = request.getLangParam();

    if (!index && !collection && (!targets || targets.length === 0)) {
      throw kerror.get(
        "api",
        "assert",
        "missing_argument",
        "index, collection or targets",
      );
    }

    if (
      index &&
      collection &&
      (hasMultiTargets(index) || hasMultiTargets(collection))
    ) {
      throw kerror.get(
        "services",
        "storage",
        "invalid_multi_index_collection_usage",
      );
    }

    if (targets.length > 0) {
      // Index and Collections from a target should not contains any characters for multi targetting or _all
      // Otherwise it might be possible to bypass some checks and access data that should be accessed
      // We should also verify that each target has an index and collections specified before further processing
      this.assertTargetsAreValid(targets);
    }

    this.assertNotExceedMaxFetch(size - from);

    if (lang === "koncorde") {
      searchBody.query = await this.translateKoncorde(searchBody.query || {});
    }

    let result;
    if (targets.length > 0) {
      result = await this.ask(
        "core:storage:public:document:multiSearch",
        targets,
        searchBody,
        { from, scroll: scrollTTL, size },
      );
    } else {
      if (!index) {
        throw kerror.get("api", "assert", "missing_argument", "index");
      }

      if (!collection) {
        throw kerror.get("api", "assert", "missing_argument", "collection");
      }

      result = await this.ask(
        "core:storage:public:document:search",
        index,
        collection,
        searchBody,
        { from, scroll: scrollTTL, size },
      );
    }

    return {
      aggregations: result.aggregations,
      hits: result.hits,
      remaining: result.remaining,
      scrollId: result.scrollId,
      suggest: result.suggest,
      total: result.total,
    };
  }
@param {Request} request
@returns {Promise<Object>}