This is an automated email from the ASF dual-hosted git repository.

twice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git


The following commit(s) were added to refs/heads/unstable by this push:
     new bd3c0532 Implement the new encoding for search framework (#2338)
bd3c0532 is described below

commit bd3c0532e6f959098331e51f0b9459a4ce872d17
Author: Twice <[email protected]>
AuthorDate: Fri May 31 00:08:09 2024 +0900

    Implement the new encoding for search framework (#2338)
---
 src/search/executors/filter_executor.h             |   2 +-
 src/search/executors/numeric_field_scan_executor.h |  45 ++---
 src/search/executors/tag_field_scan_executor.h     |  48 +++---
 src/search/index_info.h                            |  12 +-
 src/search/indexer.cc                              | 159 +++++++++--------
 src/search/indexer.h                               |   7 +-
 src/search/ir_sema_checker.h                       |   4 +-
 src/search/passes/index_selection.h                |   2 +-
 src/search/search_encoding.h                       | 190 ++++++++++++++++-----
 src/storage/redis_metadata.cc                      |  19 +--
 src/storage/redis_metadata.h                       |  16 --
 tests/cppunit/indexer_test.cc                      | 112 +++++-------
 tests/cppunit/ir_dot_dumper_test.cc                |  13 +-
 tests/cppunit/ir_pass_test.cc                      |  12 +-
 tests/cppunit/ir_sema_checker_test.cc              |   8 +-
 tests/cppunit/plan_executor_test.cc                |  10 +-
 16 files changed, 358 insertions(+), 301 deletions(-)

diff --git a/src/search/executors/filter_executor.h 
b/src/search/executors/filter_executor.h
index 6820ae58..ea860fc6 100644
--- a/src/search/executors/filter_executor.h
+++ b/src/search/executors/filter_executor.h
@@ -74,7 +74,7 @@ struct QueryExprEvaluator {
 
   StatusOr<bool> Visit(TagContainExpr *v) const {
     auto val = GET_OR_RET(ctx->Retrieve(row, v->field->info));
-    auto meta = v->field->info->MetadataAs<redis::SearchTagFieldMetadata>();
+    auto meta = v->field->info->MetadataAs<redis::TagFieldMetadata>();
 
     auto split = util::Split(val, std::string(1, meta->separator));
     return std::find(split.begin(), split.end(), v->tag->val) != split.end();
diff --git a/src/search/executors/numeric_field_scan_executor.h 
b/src/search/executors/numeric_field_scan_executor.h
index 970ef106..e9699aa4 100644
--- a/src/search/executors/numeric_field_scan_executor.h
+++ b/src/search/executors/numeric_field_scan_executor.h
@@ -38,35 +38,38 @@ struct NumericFieldScanExecutor : ExecutorNode {
   util::UniqueIterator iter{nullptr};
 
   IndexInfo *index;
-  std::string ns_key;
+  redis::SearchKey search_key;
 
   NumericFieldScanExecutor(ExecutorContext *ctx, NumericFieldScan *scan)
-      : ExecutorNode(ctx), scan(scan), ss(ctx->storage), 
index(scan->field->info->index) {
-    ns_key = ComposeNamespaceKey(index->ns, index->name, 
ctx->storage->IsSlotIdEncoded());
-  }
+      : ExecutorNode(ctx),
+        scan(scan),
+        ss(ctx->storage),
+        index(scan->field->info->index),
+        search_key(index->ns, index->name, scan->field->name) {}
 
-  std::string IndexKey(double num) {
-    return InternalKey(ns_key, 
redis::ConstructNumericFieldSubkey(scan->field->name, num, {}), 
index->metadata.version,
-                       ctx->storage->IsSlotIdEncoded())
-        .Encode();
-  }
+  std::string IndexKey(double num) const { return 
search_key.ConstructNumericFieldData(num, {}); }
 
-  bool InRangeDecode(Slice key, Slice field, double num, double *curr, Slice 
*user_key) {
-    auto ikey = InternalKey(key, ctx->storage->IsSlotIdEncoded());
-    if (ikey.GetVersion() != index->metadata.version) return false;
-    auto subkey = ikey.GetSubKey();
+  bool InRangeDecode(Slice key, double *curr, Slice *user_key) const {
+    uint8_t ns_size = 0;
+    if (!GetFixed8(&key, &ns_size)) return false;
+    if (ns_size != index->ns.size()) return false;
+    if (!key.starts_with(index->ns)) return false;
+    key.remove_prefix(ns_size);
 
-    uint8_t flag = 0;
-    if (!GetFixed8(&subkey, &flag)) return false;
-    if (flag != (uint8_t)redis::SearchSubkeyType::NUMERIC_FIELD) return false;
+    uint8_t subkey_type = 0;
+    if (!GetFixed8(&key, &subkey_type)) return false;
+    if (subkey_type != (uint8_t)redis::SearchSubkeyType::FIELD) return false;
 
     Slice value;
-    if (!GetSizedString(&subkey, &value)) return false;
-    if (value != field) return false;
+    if (!GetSizedString(&key, &value)) return false;
+    if (value != index->name) return false;
+
+    if (!GetSizedString(&key, &value)) return false;
+    if (value != scan->field->name) return false;
 
-    if (!GetDouble(&subkey, curr)) return false;
+    if (!GetDouble(&key, curr)) return false;
 
-    if (!GetSizedString(&subkey, user_key)) return false;
+    if (!GetSizedString(&key, user_key)) return false;
 
     return true;
   }
@@ -90,7 +93,7 @@ struct NumericFieldScanExecutor : ExecutorNode {
 
     double curr = 0;
     Slice user_key;
-    if (!InRangeDecode(iter->key(), scan->field->name, scan->range.r, &curr, 
&user_key)) {
+    if (!InRangeDecode(iter->key(), &curr, &user_key)) {
       return end;
     }
 
diff --git a/src/search/executors/tag_field_scan_executor.h 
b/src/search/executors/tag_field_scan_executor.h
index ddedffc9..9eff2e66 100644
--- a/src/search/executors/tag_field_scan_executor.h
+++ b/src/search/executors/tag_field_scan_executor.h
@@ -38,35 +38,37 @@ struct TagFieldScanExecutor : ExecutorNode {
   util::UniqueIterator iter{nullptr};
 
   IndexInfo *index;
-  std::string ns_key;
   std::string index_key;
 
   TagFieldScanExecutor(ExecutorContext *ctx, TagFieldScan *scan)
-      : ExecutorNode(ctx), scan(scan), ss(ctx->storage), 
index(scan->field->info->index) {
-    ns_key = ComposeNamespaceKey(index->ns, index->name, 
ctx->storage->IsSlotIdEncoded());
-    index_key = InternalKey(ns_key, 
redis::ConstructTagFieldSubkey(scan->field->name, scan->tag, {}),
-                            index->metadata.version, 
ctx->storage->IsSlotIdEncoded())
-                    .Encode();
-  }
-
-  bool InRangeDecode(Slice key, Slice field, Slice *user_key) {
-    auto ikey = InternalKey(key, ctx->storage->IsSlotIdEncoded());
-    if (ikey.GetVersion() != index->metadata.version) return false;
-    auto subkey = ikey.GetSubKey();
-
-    uint8_t flag = 0;
-    if (!GetFixed8(&subkey, &flag)) return false;
-    if (flag != (uint8_t)redis::SearchSubkeyType::TAG_FIELD) return false;
+      : ExecutorNode(ctx),
+        scan(scan),
+        ss(ctx->storage),
+        index(scan->field->info->index),
+        index_key(redis::SearchKey(index->ns, index->name, 
scan->field->name).ConstructTagFieldData(scan->tag, {})) {}
+
+  bool InRangeDecode(Slice key, Slice *user_key) const {
+    uint8_t ns_size = 0;
+    if (!GetFixed8(&key, &ns_size)) return false;
+    if (ns_size != index->ns.size()) return false;
+    if (!key.starts_with(index->ns)) return false;
+    key.remove_prefix(ns_size);
+
+    uint8_t subkey_type = 0;
+    if (!GetFixed8(&key, &subkey_type)) return false;
+    if (subkey_type != (uint8_t)redis::SearchSubkeyType::FIELD) return false;
 
     Slice value;
-    if (!GetSizedString(&subkey, &value)) return false;
-    if (value != field) return false;
+    if (!GetSizedString(&key, &value)) return false;
+    if (value != index->name) return false;
+
+    if (!GetSizedString(&key, &value)) return false;
+    if (value != scan->field->name) return false;
 
-    Slice tag;
-    if (!GetSizedString(&subkey, &tag)) return false;
-    if (tag != scan->tag) return false;
+    if (!GetSizedString(&key, &value)) return false;
+    if (value != scan->tag) return false;
 
-    if (!GetSizedString(&subkey, user_key)) return false;
+    if (!GetSizedString(&key, user_key)) return false;
 
     return true;
   }
@@ -85,7 +87,7 @@ struct TagFieldScanExecutor : ExecutorNode {
     }
 
     Slice user_key;
-    if (!InRangeDecode(iter->key(), scan->field->name, &user_key)) {
+    if (!InRangeDecode(iter->key(), &user_key)) {
       return end;
     }
 
diff --git a/src/search/index_info.h b/src/search/index_info.h
index 1751549d..59abc694 100644
--- a/src/search/index_info.h
+++ b/src/search/index_info.h
@@ -33,12 +33,12 @@ struct IndexInfo;
 struct FieldInfo {
   std::string name;
   IndexInfo *index = nullptr;
-  std::unique_ptr<redis::SearchFieldMetadata> metadata;
+  std::unique_ptr<redis::IndexFieldMetadata> metadata;
 
-  FieldInfo(std::string name, std::unique_ptr<redis::SearchFieldMetadata> 
&&metadata)
+  FieldInfo(std::string name, std::unique_ptr<redis::IndexFieldMetadata> 
&&metadata)
       : name(std::move(name)), metadata(std::move(metadata)) {}
 
-  bool IsSortable() const { return 
dynamic_cast<redis::SearchSortableFieldMetadata *>(metadata.get()) != nullptr; }
+  bool IsSortable() const { return metadata->IsSortable(); }
   bool HasIndex() const { return !metadata->noindex; }
 
   template <typename T>
@@ -51,12 +51,12 @@ struct IndexInfo {
   using FieldMap = std::map<std::string, FieldInfo>;
 
   std::string name;
-  SearchMetadata metadata;
+  redis::IndexMetadata metadata;
   FieldMap fields;
-  redis::SearchPrefixesMetadata prefixes;
+  redis::IndexPrefixes prefixes;
   std::string ns;
 
-  IndexInfo(std::string name, SearchMetadata metadata) : 
name(std::move(name)), metadata(std::move(metadata)) {}
+  IndexInfo(std::string name, redis::IndexMetadata metadata) : 
name(std::move(name)), metadata(std::move(metadata)) {}
 
   void Add(FieldInfo &&field) {
     const auto &name = field.name;
diff --git a/src/search/indexer.cc b/src/search/indexer.cc
index 4bce72de..752d42bd 100644
--- a/src/search/indexer.cc
+++ b/src/search/indexer.cc
@@ -32,16 +32,16 @@
 
 namespace redis {
 
-StatusOr<FieldValueRetriever> FieldValueRetriever::Create(SearchOnDataType 
type, std::string_view key,
+StatusOr<FieldValueRetriever> FieldValueRetriever::Create(IndexOnDataType 
type, std::string_view key,
                                                           engine::Storage 
*storage, const std::string &ns) {
-  if (type == SearchOnDataType::HASH) {
+  if (type == IndexOnDataType::HASH) {
     Hash db(storage, ns);
     std::string ns_key = db.AppendNamespacePrefix(key);
     HashMetadata metadata(false);
     auto s = db.GetMetadata(Database::GetOptions{}, ns_key, &metadata);
     if (!s.ok()) return {Status::NotOK, s.ToString()};
     return FieldValueRetriever(db, metadata, key);
-  } else if (type == SearchOnDataType::JSON) {
+  } else if (type == IndexOnDataType::JSON) {
     Json db(storage, ns);
     std::string ns_key = db.AppendNamespacePrefix(key);
     JsonMetadata metadata(false);
@@ -50,7 +50,7 @@ StatusOr<FieldValueRetriever> 
FieldValueRetriever::Create(SearchOnDataType type,
     if (!s.ok()) return {Status::NotOK, s.ToString()};
     return FieldValueRetriever(value);
   } else {
-    assert(false && "unreachable code: unexpected SearchOnDataType");
+    assert(false && "unreachable code: unexpected IndexOnDataType");
     __builtin_unreachable();
   }
 }
@@ -111,94 +111,103 @@ StatusOr<IndexUpdater::FieldValues> 
IndexUpdater::Record(std::string_view key, c
   return values;
 }
 
-Status IndexUpdater::UpdateIndex(const std::string &field, std::string_view 
key, std::string_view original,
-                                 std::string_view current, const std::string 
&ns) const {
-  if (original == current) {
-    // the value of this field is unchanged, no need to update
-    return Status::OK();
+Status IndexUpdater::UpdateTagIndex(std::string_view key, std::string_view 
original, std::string_view current,
+                                    const SearchKey &search_key, const 
TagFieldMetadata *tag) const {
+  const char delim[] = {tag->separator, '\0'};
+  auto original_tags = util::Split(original, delim);
+  auto current_tags = util::Split(current, delim);
+
+  auto to_tag_set = [](const std::vector<std::string> &tags, bool 
case_sensitive) -> std::set<std::string> {
+    if (case_sensitive) {
+      return {tags.begin(), tags.end()};
+    } else {
+      std::set<std::string> res;
+      std::transform(tags.begin(), tags.end(), std::inserter(res, 
res.begin()), util::ToLower);
+      return res;
+    }
+  };
+
+  std::set<std::string> tags_to_delete = to_tag_set(original_tags, 
tag->case_sensitive);
+  std::set<std::string> tags_to_add = to_tag_set(current_tags, 
tag->case_sensitive);
+
+  for (auto it = tags_to_delete.begin(); it != tags_to_delete.end();) {
+    if (auto jt = tags_to_add.find(*it); jt != tags_to_add.end()) {
+      it = tags_to_delete.erase(it);
+      tags_to_add.erase(jt);
+    } else {
+      ++it;
+    }
   }
 
-  auto iter = info->fields.find(field);
-  if (iter == info->fields.end()) {
-    return {Status::NotOK, "No such field to do index updating"};
+  if (tags_to_add.empty() && tags_to_delete.empty()) {
+    // no change, skip index updating
+    return Status::OK();
   }
 
-  auto *metadata = iter->second.metadata.get();
   auto *storage = indexer->storage;
-  auto ns_key = ComposeNamespaceKey(ns, info->name, 
storage->IsSlotIdEncoded());
-  if (auto tag = dynamic_cast<SearchTagFieldMetadata *>(metadata)) {
-    const char delim[] = {tag->separator, '\0'};
-    auto original_tags = util::Split(original, delim);
-    auto current_tags = util::Split(current, delim);
-
-    auto to_tag_set = [](const std::vector<std::string> &tags, bool 
case_sensitive) -> std::set<std::string> {
-      if (case_sensitive) {
-        return {tags.begin(), tags.end()};
-      } else {
-        std::set<std::string> res;
-        std::transform(tags.begin(), tags.end(), std::inserter(res, 
res.begin()), util::ToLower);
-        return res;
-      }
-    };
-
-    std::set<std::string> tags_to_delete = to_tag_set(original_tags, 
tag->case_sensitive);
-    std::set<std::string> tags_to_add = to_tag_set(current_tags, 
tag->case_sensitive);
-
-    for (auto it = tags_to_delete.begin(); it != tags_to_delete.end();) {
-      if (auto jt = tags_to_add.find(*it); jt != tags_to_add.end()) {
-        it = tags_to_delete.erase(it);
-        tags_to_add.erase(jt);
-      } else {
-        ++it;
-      }
-    }
+  auto batch = storage->GetWriteBatchBase();
+  auto cf_handle = storage->GetCFHandle(ColumnFamilyID::Search);
 
-    if (tags_to_add.empty() && tags_to_delete.empty()) {
-      // no change, skip index updating
-      return Status::OK();
-    }
+  for (const auto &tag : tags_to_delete) {
+    auto index_key = search_key.ConstructTagFieldData(tag, key);
 
-    auto batch = storage->GetWriteBatchBase();
-    auto cf_handle = storage->GetCFHandle(ColumnFamilyID::Search);
+    batch->Delete(cf_handle, index_key);
+  }
 
-    for (const auto &tag : tags_to_delete) {
-      auto sub_key = ConstructTagFieldSubkey(field, tag, key);
-      auto index_key = InternalKey(ns_key, sub_key, info->metadata.version, 
storage->IsSlotIdEncoded());
+  for (const auto &tag : tags_to_add) {
+    auto index_key = search_key.ConstructTagFieldData(tag, key);
 
-      batch->Delete(cf_handle, index_key.Encode());
-    }
+    batch->Put(cf_handle, index_key, Slice());
+  }
 
-    for (const auto &tag : tags_to_add) {
-      auto sub_key = ConstructTagFieldSubkey(field, tag, key);
-      auto index_key = InternalKey(ns_key, sub_key, info->metadata.version, 
storage->IsSlotIdEncoded());
+  auto s = storage->Write(storage->DefaultWriteOptions(), 
batch->GetWriteBatch());
+  if (!s.ok()) return {Status::NotOK, s.ToString()};
+  return Status::OK();
+}
 
-      batch->Put(cf_handle, index_key.Encode(), Slice());
-    }
+Status IndexUpdater::UpdateNumericIndex(std::string_view key, std::string_view 
original, std::string_view current,
+                                        const SearchKey &search_key, const 
NumericFieldMetadata *num) const {
+  auto *storage = indexer->storage;
+  auto batch = storage->GetWriteBatchBase();
+  auto cf_handle = storage->GetCFHandle(ColumnFamilyID::Search);
 
-    auto s = storage->Write(storage->DefaultWriteOptions(), 
batch->GetWriteBatch());
-    if (!s.ok()) return {Status::NotOK, s.ToString()};
-  } else if (auto numeric [[maybe_unused]] = 
dynamic_cast<SearchNumericFieldMetadata *>(metadata)) {
-    auto batch = storage->GetWriteBatchBase();
-    auto cf_handle = storage->GetCFHandle(ColumnFamilyID::Search);
+  if (!original.empty()) {
+    auto original_num = GET_OR_RET(ParseFloat(std::string(original.begin(), 
original.end())));
+    auto index_key = search_key.ConstructNumericFieldData(original_num, key);
 
-    if (!original.empty()) {
-      auto original_num = GET_OR_RET(ParseFloat(std::string(original.begin(), 
original.end())));
-      auto sub_key = ConstructNumericFieldSubkey(field, original_num, key);
-      auto index_key = InternalKey(ns_key, sub_key, info->metadata.version, 
storage->IsSlotIdEncoded());
+    batch->Delete(cf_handle, index_key);
+  }
 
-      batch->Delete(cf_handle, index_key.Encode());
-    }
+  if (!current.empty()) {
+    auto current_num = GET_OR_RET(ParseFloat(std::string(current.begin(), 
current.end())));
+    auto index_key = search_key.ConstructNumericFieldData(current_num, key);
 
-    if (!current.empty()) {
-      auto current_num = GET_OR_RET(ParseFloat(std::string(current.begin(), 
current.end())));
-      auto sub_key = ConstructNumericFieldSubkey(field, current_num, key);
-      auto index_key = InternalKey(ns_key, sub_key, info->metadata.version, 
storage->IsSlotIdEncoded());
+    batch->Put(cf_handle, index_key, Slice());
+  }
 
-      batch->Put(cf_handle, index_key.Encode(), Slice());
-    }
+  auto s = storage->Write(storage->DefaultWriteOptions(), 
batch->GetWriteBatch());
+  if (!s.ok()) return {Status::NotOK, s.ToString()};
+  return Status::OK();
+}
 
-    auto s = storage->Write(storage->DefaultWriteOptions(), 
batch->GetWriteBatch());
-    if (!s.ok()) return {Status::NotOK, s.ToString()};
+Status IndexUpdater::UpdateIndex(const std::string &field, std::string_view 
key, std::string_view original,
+                                 std::string_view current, const std::string 
&ns) const {
+  if (original == current) {
+    // the value of this field is unchanged, no need to update
+    return Status::OK();
+  }
+
+  auto iter = info->fields.find(field);
+  if (iter == info->fields.end()) {
+    return {Status::NotOK, "No such field to do index updating"};
+  }
+
+  auto *metadata = iter->second.metadata.get();
+  SearchKey search_key(ns, info->name, field);
+  if (auto tag = dynamic_cast<TagFieldMetadata *>(metadata)) {
+    GET_OR_RET(UpdateTagIndex(key, original, current, search_key, tag));
+  } else if (auto numeric [[maybe_unused]] = dynamic_cast<NumericFieldMetadata 
*>(metadata)) {
+    GET_OR_RET(UpdateNumericIndex(key, original, current, search_key, 
numeric));
   } else {
     return {Status::NotOK, "Unexpected field type"};
   }
diff --git a/src/search/indexer.h b/src/search/indexer.h
index dc1f03e0..d6bf37de 100644
--- a/src/search/indexer.h
+++ b/src/search/indexer.h
@@ -56,7 +56,7 @@ struct FieldValueRetriever {
   using Variant = std::variant<HashData, JsonData>;
   Variant db;
 
-  static StatusOr<FieldValueRetriever> Create(SearchOnDataType type, 
std::string_view key, engine::Storage *storage,
+  static StatusOr<FieldValueRetriever> Create(IndexOnDataType type, 
std::string_view key, engine::Storage *storage,
                                               const std::string &ns);
 
   explicit FieldValueRetriever(Hash hash, HashMetadata metadata, 
std::string_view key)
@@ -79,6 +79,11 @@ struct IndexUpdater {
   Status UpdateIndex(const std::string &field, std::string_view key, 
std::string_view original,
                      std::string_view current, const std::string &ns) const;
   Status Update(const FieldValues &original, std::string_view key, const 
std::string &ns) const;
+
+  Status UpdateTagIndex(std::string_view key, std::string_view original, 
std::string_view current,
+                        const SearchKey &search_key, const TagFieldMetadata 
*tag) const;
+  Status UpdateNumericIndex(std::string_view key, std::string_view original, 
std::string_view current,
+                            const SearchKey &search_key, const 
NumericFieldMetadata *num) const;
 };
 
 struct GlobalIndexer {
diff --git a/src/search/ir_sema_checker.h b/src/search/ir_sema_checker.h
index 170e646f..5e100621 100644
--- a/src/search/ir_sema_checker.h
+++ b/src/search/ir_sema_checker.h
@@ -75,7 +75,7 @@ struct SemaChecker {
     } else if (auto v = dynamic_cast<TagContainExpr *>(node)) {
       if (auto iter = current_index->fields.find(v->field->name); iter == 
current_index->fields.end()) {
         return {Status::NotOK, fmt::format("field `{}` not found in index 
`{}`", v->field->name)};
-      } else if (auto meta = 
iter->second.MetadataAs<redis::SearchTagFieldMetadata>(); !meta) {
+      } else if (auto meta = 
iter->second.MetadataAs<redis::TagFieldMetadata>(); !meta) {
         return {Status::NotOK, fmt::format("field `{}` is not a tag field", 
v->field->name)};
       } else {
         v->field->info = &iter->second;
@@ -91,7 +91,7 @@ struct SemaChecker {
     } else if (auto v = dynamic_cast<NumericCompareExpr *>(node)) {
       if (auto iter = current_index->fields.find(v->field->name); iter == 
current_index->fields.end()) {
         return {Status::NotOK, fmt::format("field `{}` not found in index 
`{}`", v->field->name, current_index->name)};
-      } else if 
(!iter->second.MetadataAs<redis::SearchNumericFieldMetadata>()) {
+      } else if (!iter->second.MetadataAs<redis::NumericFieldMetadata>()) {
         return {Status::NotOK, fmt::format("field `{}` is not a numeric 
field", v->field->name)};
       } else {
         v->field->info = &iter->second;
diff --git a/src/search/passes/index_selection.h 
b/src/search/passes/index_selection.h
index 4ced7972..e60287d4 100644
--- a/src/search/passes/index_selection.h
+++ b/src/search/passes/index_selection.h
@@ -72,7 +72,7 @@ struct IndexSelection : Visitor {
   bool HasGoodOrder() const { return order && order->field->info->HasIndex(); }
 
   std::unique_ptr<PlanOperator> GenerateScanFromOrder() const {
-    if (order->field->info->MetadataAs<redis::SearchNumericFieldMetadata>()) {
+    if (order->field->info->MetadataAs<redis::NumericFieldMetadata>()) {
       return 
std::make_unique<NumericFieldScan>(order->field->CloneAs<FieldRef>(), 
Interval::Full(), order->order);
     } else {
       CHECK(false) << "current only numeric field is supported for ordering";
diff --git a/src/search/search_encoding.h b/src/search/search_encoding.h
index 32f244ca..3819fd9b 100644
--- a/src/search/search_encoding.h
+++ b/src/search/search_encoding.h
@@ -23,26 +23,127 @@
 #include <encoding.h>
 #include <storage/redis_metadata.h>
 
+#include <memory>
+
 namespace redis {
 
+enum class IndexOnDataType : uint8_t {
+  HASH = kRedisHash,
+  JSON = kRedisJson,
+};
+
 inline constexpr auto kErrorInsufficientLength = "insufficient length while 
decoding metadata";
 
+class IndexMetadata {
+ public:
+  uint8_t flag = 0;  // all reserved
+  IndexOnDataType on_data_type;
+
+  void Encode(std::string *dst) const {
+    PutFixed8(dst, flag);
+    PutFixed8(dst, uint8_t(on_data_type));
+  }
+
+  rocksdb::Status Decode(Slice *input) {
+    if (!GetFixed8(input, &flag)) {
+      return rocksdb::Status::InvalidArgument(kErrorInsufficientLength);
+    }
+
+    if (!GetFixed8(input, reinterpret_cast<uint8_t *>(&on_data_type))) {
+      return rocksdb::Status::InvalidArgument(kErrorInsufficientLength);
+    }
+
+    return rocksdb::Status::OK();
+  }
+};
+
 enum class SearchSubkeyType : uint8_t {
-  // search global metadata
+  INDEX_META = 0,
+
   PREFIXES = 1,
 
-  // field metadata for different types
-  TAG_FIELD_META = 64 + 1,
-  NUMERIC_FIELD_META = 64 + 2,
+  // field metadata
+  FIELD_META = 2,
+
+  // field indexing data
+  FIELD = 3,
 
-  // field indexing for different types
-  TAG_FIELD = 128 + 1,
-  NUMERIC_FIELD = 128 + 2,
+  // field alias
+  FIELD_ALIAS = 4,
 };
 
-inline std::string ConstructSearchPrefixesSubkey() { return 
{(char)SearchSubkeyType::PREFIXES}; }
+enum class IndexFieldType : uint8_t {
+  TAG = 1,
+
+  NUMERIC = 2,
+};
+
+struct SearchKey {
+  std::string_view ns;
+  std::string_view index;
+  std::string_view field;
+
+  SearchKey(std::string_view ns, std::string_view index) : ns(ns), 
index(index) {}
+  SearchKey(std::string_view ns, std::string_view index, std::string_view 
field) : ns(ns), index(index), field(field) {}
+
+  void PutNamespace(std::string *dst) const {
+    PutFixed8(dst, ns.size());
+    dst->append(ns);
+  }
+
+  static void PutType(std::string *dst, SearchSubkeyType type) { 
PutFixed8(dst, uint8_t(type)); }
+
+  void PutIndex(std::string *dst) const { PutSizedString(dst, index); }
+
+  std::string ConstructIndexMeta() const {
+    std::string dst;
+    PutNamespace(&dst);
+    PutType(&dst, SearchSubkeyType::INDEX_META);
+    PutIndex(&dst);
+    return dst;
+  }
+
+  std::string ConstructIndexPrefixes() const {
+    std::string dst;
+    PutNamespace(&dst);
+    PutType(&dst, SearchSubkeyType::PREFIXES);
+    PutIndex(&dst);
+    return dst;
+  }
+
+  std::string ConstructFieldMeta() const {
+    std::string dst;
+    PutNamespace(&dst);
+    PutType(&dst, SearchSubkeyType::FIELD_META);
+    PutIndex(&dst);
+    PutSizedString(&dst, field);
+    return dst;
+  }
+
+  std::string ConstructTagFieldData(std::string_view tag, std::string_view 
key) const {
+    std::string dst;
+    PutNamespace(&dst);
+    PutType(&dst, SearchSubkeyType::FIELD);
+    PutIndex(&dst);
+    PutSizedString(&dst, field);
+    PutSizedString(&dst, tag);
+    PutSizedString(&dst, key);
+    return dst;
+  }
+
+  std::string ConstructNumericFieldData(double num, std::string_view key) 
const {
+    std::string dst;
+    PutNamespace(&dst);
+    PutType(&dst, SearchSubkeyType::FIELD);
+    PutIndex(&dst);
+    PutSizedString(&dst, field);
+    PutDouble(&dst, num);
+    PutSizedString(&dst, key);
+    return dst;
+  }
+};
 
-struct SearchPrefixesMetadata {
+struct IndexPrefixes {
   std::vector<std::string> prefixes;
 
   static inline const std::string all[] = {""};
@@ -75,15 +176,21 @@ struct SearchPrefixesMetadata {
   }
 };
 
-struct SearchFieldMetadata {
+struct IndexFieldMetadata {
   bool noindex = false;
+  IndexFieldType type;
 
-  // flag: <noindex: 1 bit> <reserved: 7 bit>
-  uint8_t MakeFlag() const { return noindex; }
+  // flag: <noindex: 1 bit> <type: 4 bit> <reserved: 3 bit>
+  uint8_t MakeFlag() const { return noindex | (uint8_t)type << 1; }
 
-  void DecodeFlag(uint8_t flag) { noindex = flag & 1; }
+  void DecodeFlag(uint8_t flag) {
+    noindex = flag & 1;
+    type = DecodeType(flag);
+  }
+
+  static IndexFieldType DecodeType(uint8_t flag) { return IndexFieldType(flag 
>> 1); }
 
-  virtual ~SearchFieldMetadata() = default;
+  virtual ~IndexFieldMetadata() = default;
 
   virtual void Encode(std::string *dst) const { PutFixed8(dst, MakeFlag()); }
 
@@ -96,26 +203,24 @@ struct SearchFieldMetadata {
     DecodeFlag(flag);
     return rocksdb::Status::OK();
   }
-};
 
-inline std::string ConstructTagFieldMetadataSubkey(std::string_view 
field_name) {
-  std::string res = {(char)SearchSubkeyType::TAG_FIELD_META};
-  res.append(field_name);
-  return res;
-}
+  virtual bool IsSortable() const { return false; }
+
+  static inline rocksdb::Status Decode(Slice *input, 
std::unique_ptr<IndexFieldMetadata> &ptr);
+};
 
-struct SearchTagFieldMetadata : SearchFieldMetadata {
+struct TagFieldMetadata : IndexFieldMetadata {
   char separator = ',';
   bool case_sensitive = false;
 
   void Encode(std::string *dst) const override {
-    SearchFieldMetadata::Encode(dst);
+    IndexFieldMetadata::Encode(dst);
     PutFixed8(dst, separator);
     PutFixed8(dst, case_sensitive);
   }
 
   rocksdb::Status Decode(Slice *input) override {
-    if (auto s = SearchFieldMetadata::Decode(input); !s.ok()) {
+    if (auto s = IndexFieldMetadata::Decode(input); !s.ok()) {
       return s;
     }
 
@@ -129,30 +234,27 @@ struct SearchTagFieldMetadata : SearchFieldMetadata {
   }
 };
 
-inline std::string ConstructNumericFieldMetadataSubkey(std::string_view 
field_name) {
-  std::string res = {(char)SearchSubkeyType::NUMERIC_FIELD_META};
-  res.append(field_name);
-  return res;
-}
-
-struct SearchSortableFieldMetadata : SearchFieldMetadata {};
+struct NumericFieldMetadata : IndexFieldMetadata {
+  bool IsSortable() const override { return true; }
+};
 
-struct SearchNumericFieldMetadata : SearchSortableFieldMetadata {};
+inline rocksdb::Status IndexFieldMetadata::Decode(Slice *input, 
std::unique_ptr<IndexFieldMetadata> &ptr) {
+  if (input->size() < 1) {
+    return rocksdb::Status::Corruption(kErrorInsufficientLength);
+  }
 
-inline std::string ConstructTagFieldSubkey(std::string_view field_name, 
std::string_view tag, std::string_view key) {
-  std::string res = {(char)SearchSubkeyType::TAG_FIELD};
-  PutSizedString(&res, field_name);
-  PutSizedString(&res, tag);
-  PutSizedString(&res, key);
-  return res;
-}
+  switch (DecodeType((*input)[0])) {
+    case IndexFieldType::TAG:
+      ptr = std::make_unique<TagFieldMetadata>();
+      break;
+    case IndexFieldType::NUMERIC:
+      ptr = std::make_unique<NumericFieldMetadata>();
+      break;
+    default:
+      return rocksdb::Status::Corruption("encountered unknown field type");
+  }
 
-inline std::string ConstructNumericFieldSubkey(std::string_view field_name, 
double number, std::string_view key) {
-  std::string res = {(char)SearchSubkeyType::NUMERIC_FIELD};
-  PutSizedString(&res, field_name);
-  PutDouble(&res, number);
-  PutSizedString(&res, key);
-  return res;
+  return ptr->Decode(input);
 }
 
 }  // namespace redis
diff --git a/src/storage/redis_metadata.cc b/src/storage/redis_metadata.cc
index 5e872af0..e44b39ca 100644
--- a/src/storage/redis_metadata.cc
+++ b/src/storage/redis_metadata.cc
@@ -96,6 +96,7 @@ std::string InternalKey::Encode() const {
 }
 
 bool InternalKey::operator==(const InternalKey &that) const {
+  if (namespace_ != this->namespace_) return false;
   if (key_ != that.key_) return false;
   if (sub_key_ != that.sub_key_) return false;
   return version_ == that.version_;
@@ -471,21 +472,3 @@ rocksdb::Status JsonMetadata::Decode(Slice *input) {
 
   return rocksdb::Status::OK();
 }
-
-void SearchMetadata::Encode(std::string *dst) const {
-  Metadata::Encode(dst);
-
-  PutFixed8(dst, uint8_t(on_data_type));
-}
-
-rocksdb::Status SearchMetadata::Decode(Slice *input) {
-  if (auto s = Metadata::Decode(input); !s.ok()) {
-    return s;
-  }
-
-  if (!GetFixed8(input, reinterpret_cast<uint8_t *>(&on_data_type))) {
-    return rocksdb::Status::InvalidArgument(kErrMetadataTooShort);
-  }
-
-  return rocksdb::Status::OK();
-}
diff --git a/src/storage/redis_metadata.h b/src/storage/redis_metadata.h
index 531a8803..68f36b2c 100644
--- a/src/storage/redis_metadata.h
+++ b/src/storage/redis_metadata.h
@@ -49,7 +49,6 @@ enum RedisType : uint8_t {
   kRedisStream = 8,
   kRedisBloomFilter = 9,
   kRedisJson = 10,
-  kRedisSearch = 11,
 };
 
 struct RedisTypes {
@@ -314,18 +313,3 @@ class JsonMetadata : public Metadata {
   void Encode(std::string *dst) const override;
   rocksdb::Status Decode(Slice *input) override;
 };
-
-enum class SearchOnDataType : uint8_t {
-  HASH = kRedisHash,
-  JSON = kRedisJson,
-};
-
-class SearchMetadata : public Metadata {
- public:
-  SearchOnDataType on_data_type;
-
-  explicit SearchMetadata(bool generate_version = true) : 
Metadata(kRedisSearch, generate_version) {}
-
-  void Encode(std::string *dst) const override;
-  rocksdb::Status Decode(Slice *input) override;
-};
diff --git a/tests/cppunit/indexer_test.cc b/tests/cppunit/indexer_test.cc
index 4ab41b3a..13779892 100644
--- a/tests/cppunit/indexer_test.cc
+++ b/tests/cppunit/indexer_test.cc
@@ -36,24 +36,24 @@ struct IndexerTest : TestBase {
   std::string ns = "index_test";
 
   IndexerTest() : indexer(storage_.get()) {
-    SearchMetadata hash_field_meta(false);
-    hash_field_meta.on_data_type = SearchOnDataType::HASH;
+    redis::IndexMetadata hash_field_meta;
+    hash_field_meta.on_data_type = redis::IndexOnDataType::HASH;
 
     auto hash_info = std::make_unique<kqir::IndexInfo>("hashtest", 
hash_field_meta);
-    hash_info->Add(kqir::FieldInfo("x", 
std::make_unique<redis::SearchTagFieldMetadata>()));
-    hash_info->Add(kqir::FieldInfo("y", 
std::make_unique<redis::SearchNumericFieldMetadata>()));
+    hash_info->Add(kqir::FieldInfo("x", 
std::make_unique<redis::TagFieldMetadata>()));
+    hash_info->Add(kqir::FieldInfo("y", 
std::make_unique<redis::NumericFieldMetadata>()));
     hash_info->prefixes.prefixes.emplace_back("idxtesthash");
 
     map.emplace("hashtest", std::move(hash_info));
 
     redis::IndexUpdater hash_updater{map.at("hashtest").get()};
 
-    SearchMetadata json_field_meta(false);
-    json_field_meta.on_data_type = SearchOnDataType::JSON;
+    redis::IndexMetadata json_field_meta;
+    json_field_meta.on_data_type = redis::IndexOnDataType::JSON;
 
     auto json_info = std::make_unique<kqir::IndexInfo>("jsontest", 
json_field_meta);
-    json_info->Add(kqir::FieldInfo("$.x", 
std::make_unique<redis::SearchTagFieldMetadata>()));
-    json_info->Add(kqir::FieldInfo("$.y", 
std::make_unique<redis::SearchNumericFieldMetadata>()));
+    json_info->Add(kqir::FieldInfo("$.x", 
std::make_unique<redis::TagFieldMetadata>()));
+    json_info->Add(kqir::FieldInfo("$.y", 
std::make_unique<redis::NumericFieldMetadata>()));
     json_info->prefixes.prefixes.emplace_back("idxtestjson");
 
     map.emplace("jsontest", std::move(json_info));
@@ -90,28 +90,22 @@ TEST_F(IndexerTest, HashTag) {
     auto s2 = indexer.Update(*s, key1, ns);
     ASSERT_TRUE(s2);
 
-    auto subkey = redis::ConstructTagFieldSubkey("x", "food", key1);
-    auto nskey = ComposeNamespaceKey(ns, idxname, false);
-    auto key = InternalKey(nskey, subkey, 0, false);
+    auto key = redis::SearchKey(ns, idxname, 
"x").ConstructTagFieldData("food", key1);
 
     std::string val;
-    auto s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key.Encode(), &val);
+    auto s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key, &val);
     ASSERT_TRUE(s3.ok());
     ASSERT_EQ(val, "");
 
-    subkey = redis::ConstructTagFieldSubkey("x", "kitchen", key1);
-    nskey = ComposeNamespaceKey(ns, idxname, false);
-    key = InternalKey(nskey, subkey, 0, false);
+    key = redis::SearchKey(ns, idxname, "x").ConstructTagFieldData("kitchen", 
key1);
 
-    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key.Encode(), &val);
+    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, key, 
&val);
     ASSERT_TRUE(s3.ok());
     ASSERT_EQ(val, "");
 
-    subkey = redis::ConstructTagFieldSubkey("x", "beauty", key1);
-    nskey = ComposeNamespaceKey(ns, idxname, false);
-    key = InternalKey(nskey, subkey, 0, false);
+    key = redis::SearchKey(ns, idxname, "x").ConstructTagFieldData("beauty", 
key1);
 
-    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key.Encode(), &val);
+    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, key, 
&val);
     ASSERT_TRUE(s3.ok());
     ASSERT_EQ(val, "");
   }
@@ -131,43 +125,33 @@ TEST_F(IndexerTest, HashTag) {
     auto s2 = indexer.Update(*s, key1, ns);
     ASSERT_TRUE(s2);
 
-    auto subkey = redis::ConstructTagFieldSubkey("x", "food", key1);
-    auto nskey = ComposeNamespaceKey(ns, idxname, false);
-    auto key = InternalKey(nskey, subkey, 0, false);
+    auto key = redis::SearchKey(ns, idxname, 
"x").ConstructTagFieldData("food", key1);
 
     std::string val;
-    auto s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key.Encode(), &val);
+    auto s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key, &val);
     ASSERT_TRUE(s3.ok());
     ASSERT_EQ(val, "");
 
-    subkey = redis::ConstructTagFieldSubkey("x", "clothing", key1);
-    nskey = ComposeNamespaceKey(ns, idxname, false);
-    key = InternalKey(nskey, subkey, 0, false);
+    key = redis::SearchKey(ns, idxname, "x").ConstructTagFieldData("clothing", 
key1);
 
-    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key.Encode(), &val);
+    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, key, 
&val);
     ASSERT_TRUE(s3.ok());
     ASSERT_EQ(val, "");
 
-    subkey = redis::ConstructTagFieldSubkey("x", "sport", key1);
-    nskey = ComposeNamespaceKey(ns, idxname, false);
-    key = InternalKey(nskey, subkey, 0, false);
+    key = redis::SearchKey(ns, idxname, "x").ConstructTagFieldData("sport", 
key1);
 
-    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key.Encode(), &val);
+    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, key, 
&val);
     ASSERT_TRUE(s3.ok());
     ASSERT_EQ(val, "");
 
-    subkey = redis::ConstructTagFieldSubkey("x", "kitchen", key1);
-    nskey = ComposeNamespaceKey(ns, idxname, false);
-    key = InternalKey(nskey, subkey, 0, false);
+    key = redis::SearchKey(ns, idxname, "x").ConstructTagFieldData("kitchen", 
key1);
 
-    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key.Encode(), &val);
+    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, key, 
&val);
     ASSERT_TRUE(s3.IsNotFound());
 
-    subkey = redis::ConstructTagFieldSubkey("x", "beauty", key1);
-    nskey = ComposeNamespaceKey(ns, idxname, false);
-    key = InternalKey(nskey, subkey, 0, false);
+    key = redis::SearchKey(ns, idxname, "x").ConstructTagFieldData("beauty", 
key1);
 
-    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key.Encode(), &val);
+    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, key, 
&val);
     ASSERT_TRUE(s3.IsNotFound());
   }
 }
@@ -196,28 +180,22 @@ TEST_F(IndexerTest, JsonTag) {
     auto s2 = indexer.Update(*s, key1, ns);
     ASSERT_TRUE(s2);
 
-    auto subkey = redis::ConstructTagFieldSubkey("$.x", "food", key1);
-    auto nskey = ComposeNamespaceKey(ns, idxname, false);
-    auto key = InternalKey(nskey, subkey, 0, false);
+    auto key = redis::SearchKey(ns, idxname, 
"$.x").ConstructTagFieldData("food", key1);
 
     std::string val;
-    auto s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key.Encode(), &val);
+    auto s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key, &val);
     ASSERT_TRUE(s3.ok());
     ASSERT_EQ(val, "");
 
-    subkey = redis::ConstructTagFieldSubkey("$.x", "kitchen", key1);
-    nskey = ComposeNamespaceKey(ns, idxname, false);
-    key = InternalKey(nskey, subkey, 0, false);
+    key = redis::SearchKey(ns, idxname, 
"$.x").ConstructTagFieldData("kitchen", key1);
 
-    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key.Encode(), &val);
+    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, key, 
&val);
     ASSERT_TRUE(s3.ok());
     ASSERT_EQ(val, "");
 
-    subkey = redis::ConstructTagFieldSubkey("$.x", "beauty", key1);
-    nskey = ComposeNamespaceKey(ns, idxname, false);
-    key = InternalKey(nskey, subkey, 0, false);
+    key = redis::SearchKey(ns, idxname, "$.x").ConstructTagFieldData("beauty", 
key1);
 
-    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key.Encode(), &val);
+    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, key, 
&val);
     ASSERT_TRUE(s3.ok());
     ASSERT_EQ(val, "");
   }
@@ -235,43 +213,33 @@ TEST_F(IndexerTest, JsonTag) {
     auto s2 = indexer.Update(*s, key1, ns);
     ASSERT_TRUE(s2);
 
-    auto subkey = redis::ConstructTagFieldSubkey("$.x", "food", key1);
-    auto nskey = ComposeNamespaceKey(ns, idxname, false);
-    auto key = InternalKey(nskey, subkey, 0, false);
+    auto key = redis::SearchKey(ns, idxname, 
"$.x").ConstructTagFieldData("food", key1);
 
     std::string val;
-    auto s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key.Encode(), &val);
+    auto s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key, &val);
     ASSERT_TRUE(s3.ok());
     ASSERT_EQ(val, "");
 
-    subkey = redis::ConstructTagFieldSubkey("$.x", "clothing", key1);
-    nskey = ComposeNamespaceKey(ns, idxname, false);
-    key = InternalKey(nskey, subkey, 0, false);
+    key = redis::SearchKey(ns, idxname, 
"$.x").ConstructTagFieldData("clothing", key1);
 
-    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key.Encode(), &val);
+    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, key, 
&val);
     ASSERT_TRUE(s3.ok());
     ASSERT_EQ(val, "");
 
-    subkey = redis::ConstructTagFieldSubkey("$.x", "sport", key1);
-    nskey = ComposeNamespaceKey(ns, idxname, false);
-    key = InternalKey(nskey, subkey, 0, false);
+    key = redis::SearchKey(ns, idxname, "$.x").ConstructTagFieldData("sport", 
key1);
 
-    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key.Encode(), &val);
+    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, key, 
&val);
     ASSERT_TRUE(s3.ok());
     ASSERT_EQ(val, "");
 
-    subkey = redis::ConstructTagFieldSubkey("$.x", "kitchen", key1);
-    nskey = ComposeNamespaceKey(ns, idxname, false);
-    key = InternalKey(nskey, subkey, 0, false);
+    key = redis::SearchKey(ns, idxname, 
"$.x").ConstructTagFieldData("kitchen", key1);
 
-    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key.Encode(), &val);
+    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, key, 
&val);
     ASSERT_TRUE(s3.IsNotFound());
 
-    subkey = redis::ConstructTagFieldSubkey("$.x", "beauty", key1);
-    nskey = ComposeNamespaceKey(ns, idxname, false);
-    key = InternalKey(nskey, subkey, 0, false);
+    key = redis::SearchKey(ns, idxname, "$.x").ConstructTagFieldData("beauty", 
key1);
 
-    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, 
key.Encode(), &val);
+    s3 = storage_->Get(storage_->DefaultMultiGetOptions(), cfhandler, key, 
&val);
     ASSERT_TRUE(s3.IsNotFound());
   }
 }
diff --git a/tests/cppunit/ir_dot_dumper_test.cc 
b/tests/cppunit/ir_dot_dumper_test.cc
index 1615b3ca..d616f290 100644
--- a/tests/cppunit/ir_dot_dumper_test.cc
+++ b/tests/cppunit/ir_dot_dumper_test.cc
@@ -27,6 +27,7 @@
 #include "search/ir_plan.h"
 #include "search/ir_sema_checker.h"
 #include "search/passes/manager.h"
+#include "search/search_encoding.h"
 #include "search/sql_transformer.h"
 
 using namespace kqir;
@@ -64,14 +65,14 @@ static auto ParseS(SemaChecker& sc, const std::string& in) {
 }
 
 static IndexMap MakeIndexMap() {
-  auto f1 = FieldInfo("t1", std::make_unique<redis::SearchTagFieldMetadata>());
-  auto f2 = FieldInfo("t2", std::make_unique<redis::SearchTagFieldMetadata>());
+  auto f1 = FieldInfo("t1", std::make_unique<redis::TagFieldMetadata>());
+  auto f2 = FieldInfo("t2", std::make_unique<redis::TagFieldMetadata>());
   f2.metadata->noindex = true;
-  auto f3 = FieldInfo("n1", 
std::make_unique<redis::SearchNumericFieldMetadata>());
-  auto f4 = FieldInfo("n2", 
std::make_unique<redis::SearchNumericFieldMetadata>());
-  auto f5 = FieldInfo("n3", 
std::make_unique<redis::SearchNumericFieldMetadata>());
+  auto f3 = FieldInfo("n1", std::make_unique<redis::NumericFieldMetadata>());
+  auto f4 = FieldInfo("n2", std::make_unique<redis::NumericFieldMetadata>());
+  auto f5 = FieldInfo("n3", std::make_unique<redis::NumericFieldMetadata>());
   f5.metadata->noindex = true;
-  auto ia = std::make_unique<IndexInfo>("ia", SearchMetadata());
+  auto ia = std::make_unique<IndexInfo>("ia", redis::IndexMetadata());
   ia->Add(std::move(f1));
   ia->Add(std::move(f2));
   ia->Add(std::move(f3));
diff --git a/tests/cppunit/ir_pass_test.cc b/tests/cppunit/ir_pass_test.cc
index 6188bb49..76318d79 100644
--- a/tests/cppunit/ir_pass_test.cc
+++ b/tests/cppunit/ir_pass_test.cc
@@ -169,14 +169,14 @@ TEST(IRPassTest, IntervalAnalysis) {
 }
 
 static IndexMap MakeIndexMap() {
-  auto f1 = FieldInfo("t1", std::make_unique<redis::SearchTagFieldMetadata>());
-  auto f2 = FieldInfo("t2", std::make_unique<redis::SearchTagFieldMetadata>());
+  auto f1 = FieldInfo("t1", std::make_unique<redis::TagFieldMetadata>());
+  auto f2 = FieldInfo("t2", std::make_unique<redis::TagFieldMetadata>());
   f2.metadata->noindex = true;
-  auto f3 = FieldInfo("n1", 
std::make_unique<redis::SearchNumericFieldMetadata>());
-  auto f4 = FieldInfo("n2", 
std::make_unique<redis::SearchNumericFieldMetadata>());
-  auto f5 = FieldInfo("n3", 
std::make_unique<redis::SearchNumericFieldMetadata>());
+  auto f3 = FieldInfo("n1", std::make_unique<redis::NumericFieldMetadata>());
+  auto f4 = FieldInfo("n2", std::make_unique<redis::NumericFieldMetadata>());
+  auto f5 = FieldInfo("n3", std::make_unique<redis::NumericFieldMetadata>());
   f5.metadata->noindex = true;
-  auto ia = std::make_unique<IndexInfo>("ia", SearchMetadata());
+  auto ia = std::make_unique<IndexInfo>("ia", redis::IndexMetadata());
   ia->Add(std::move(f1));
   ia->Add(std::move(f2));
   ia->Add(std::move(f3));
diff --git a/tests/cppunit/ir_sema_checker_test.cc 
b/tests/cppunit/ir_sema_checker_test.cc
index 678a0a0f..a12beea7 100644
--- a/tests/cppunit/ir_sema_checker_test.cc
+++ b/tests/cppunit/ir_sema_checker_test.cc
@@ -35,10 +35,10 @@ using namespace kqir;
 static auto Parse(const std::string& in) { return 
sql::ParseToIR(peg::string_input(in, "test")); }
 
 static IndexMap MakeIndexMap() {
-  auto f1 = FieldInfo("f1", std::make_unique<redis::SearchTagFieldMetadata>());
-  auto f2 = FieldInfo("f2", 
std::make_unique<redis::SearchNumericFieldMetadata>());
-  auto f3 = FieldInfo("f3", 
std::make_unique<redis::SearchNumericFieldMetadata>());
-  auto ia = std::make_unique<IndexInfo>("ia", SearchMetadata());
+  auto f1 = FieldInfo("f1", std::make_unique<redis::TagFieldMetadata>());
+  auto f2 = FieldInfo("f2", std::make_unique<redis::NumericFieldMetadata>());
+  auto f3 = FieldInfo("f3", std::make_unique<redis::NumericFieldMetadata>());
+  auto ia = std::make_unique<IndexInfo>("ia", redis::IndexMetadata());
   ia->Add(std::move(f1));
   ia->Add(std::move(f2));
   ia->Add(std::move(f3));
diff --git a/tests/cppunit/plan_executor_test.cc 
b/tests/cppunit/plan_executor_test.cc
index 0b225fc7..bad978d0 100644
--- a/tests/cppunit/plan_executor_test.cc
+++ b/tests/cppunit/plan_executor_test.cc
@@ -37,12 +37,12 @@ using namespace kqir;
 static auto exe_end = ExecutorNode::Result(ExecutorNode::end);
 
 static IndexMap MakeIndexMap() {
-  auto f1 = FieldInfo("f1", std::make_unique<redis::SearchTagFieldMetadata>());
-  auto f2 = FieldInfo("f2", 
std::make_unique<redis::SearchNumericFieldMetadata>());
-  auto f3 = FieldInfo("f3", 
std::make_unique<redis::SearchNumericFieldMetadata>());
-  auto ia = std::make_unique<IndexInfo>("ia", SearchMetadata());
+  auto f1 = FieldInfo("f1", std::make_unique<redis::TagFieldMetadata>());
+  auto f2 = FieldInfo("f2", std::make_unique<redis::NumericFieldMetadata>());
+  auto f3 = FieldInfo("f3", std::make_unique<redis::NumericFieldMetadata>());
+  auto ia = std::make_unique<IndexInfo>("ia", redis::IndexMetadata());
   ia->ns = "search_ns";
-  ia->metadata.on_data_type = SearchOnDataType::JSON;
+  ia->metadata.on_data_type = redis::IndexOnDataType::JSON;
   ia->prefixes.prefixes.emplace_back("test2:");
   ia->prefixes.prefixes.emplace_back("test4:");
   ia->Add(std::move(f1));


Reply via email to