Procházet zdrojové kódy

Merge pull request #10157 from weseek/support/168289-add-mappings-for-elasticsearch9

support: Add mappings for elasticsearch9
Yuki Takei před 9 měsíci
rodič
revize
09f4cf91a0

+ 0 - 119
apps/app/resource/search/mappings-es7.json

@@ -1,119 +0,0 @@
-{
-  "settings": {
-    "analysis": {
-      "filter": {
-        "english_stop": {
-          "type":       "stop",
-          "stopwords":  "_english_"
-        }
-      },
-      "tokenizer": {
-        "edge_ngram_tokenizer": {
-          "type": "edge_ngram",
-          "min_gram": 2,
-          "max_gram": 20,
-          "token_chars": ["letter", "digit"]
-        }
-      },
-      "analyzer": {
-        "japanese": {
-          "tokenizer": "kuromoji_tokenizer",
-          "char_filter" : ["icu_normalizer"]
-        },
-        "english_edge_ngram": {
-          "tokenizer": "edge_ngram_tokenizer",
-          "filter": [
-            "lowercase",
-            "english_stop"
-          ]
-        }
-      }
-    }
-  },
-  "mappings": {
-    "properties" : {
-      "path": {
-        "type": "text",
-        "fields": {
-          "raw": {
-            "type": "text",
-            "analyzer": "keyword"
-          },
-          "ja": {
-            "type": "text",
-            "analyzer": "japanese"
-          },
-          "en": {
-            "type": "text",
-            "analyzer": "english_edge_ngram",
-            "search_analyzer": "standard"
-          }
-        }
-      },
-      "body": {
-        "type": "text",
-        "fields": {
-          "ja": {
-            "type": "text",
-            "analyzer": "japanese"
-          },
-          "en": {
-            "type": "text",
-            "analyzer": "english_edge_ngram",
-            "search_analyzer": "standard"
-          }
-        }
-      },
-      "body_embedded": {
-        "type": "dense_vector",
-        "dims": 768
-      },
-      "comments": {
-        "type": "text",
-        "fields": {
-          "ja": {
-            "type": "text",
-            "analyzer": "japanese"
-          },
-          "en": {
-            "type": "text",
-            "analyzer": "english_edge_ngram",
-            "search_analyzer": "standard"
-          }
-        }
-      },
-      "username": {
-        "type": "keyword"
-      },
-      "comment_count": {
-        "type": "integer"
-      },
-      "bookmark_count": {
-        "type": "integer"
-      },
-      "like_count": {
-        "type": "integer"
-      },
-      "grant": {
-        "type": "integer"
-      },
-      "granted_users": {
-        "type": "keyword"
-      },
-      "granted_groups": {
-        "type": "keyword"
-      },
-      "created_at": {
-        "type": "date",
-        "format": "dateOptionalTime"
-      },
-      "updated_at": {
-        "type": "date",
-        "format": "dateOptionalTime"
-      },
-      "tag_names": {
-        "type": "keyword"
-      }
-    }
-  }
-}

+ 129 - 0
apps/app/resource/search/mappings-es7.ts

@@ -0,0 +1,129 @@
+// TODO: https://redmine.weseek.co.jp/issues/168446
+import type { estypes } from '@elastic/elasticsearch7';
+
+type Mappings = {
+  settings: NonNullable<estypes.IndicesCreateRequest['body']>['settings'];
+  mappings: NonNullable<estypes.IndicesCreateRequest['body']>['mappings'];
+}
+
+export const mappings: Mappings = {
+  settings: {
+    analysis: {
+      filter: {
+        english_stop: {
+          type:       'stop',
+          stopwords:  '_english_',
+        },
+      },
+      tokenizer: {
+        edge_ngram_tokenizer: {
+          type: 'edge_ngram',
+          min_gram: 2,
+          max_gram: 20,
+          token_chars: ['letter', 'digit'],
+        },
+      },
+      analyzer: {
+        japanese: {
+          type: 'custom',
+          tokenizer: 'kuromoji_tokenizer',
+          char_filter: ['icu_normalizer'],
+        },
+        english_edge_ngram: {
+          type: 'custom',
+          tokenizer: 'edge_ngram_tokenizer',
+          filter: [
+            'lowercase',
+            'english_stop',
+          ],
+        },
+      },
+    },
+  },
+  mappings: {
+    properties: {
+      path: {
+        type: 'text',
+        fields: {
+          raw: {
+            type: 'text',
+            analyzer: 'keyword',
+          },
+          ja: {
+            type: 'text',
+            analyzer: 'japanese',
+          },
+          en: {
+            type: 'text',
+            analyzer: 'english_edge_ngram',
+            search_analyzer: 'standard',
+          },
+        },
+      },
+      body: {
+        type: 'text',
+        fields: {
+          ja: {
+            type: 'text',
+            analyzer: 'japanese',
+          },
+          en: {
+            type: 'text',
+            analyzer: 'english_edge_ngram',
+            search_analyzer: 'standard',
+          },
+        },
+      },
+      body_embedded: {
+        type: 'dense_vector',
+        dims: 768,
+      },
+      comments: {
+        type: 'text',
+        fields: {
+          ja: {
+            type: 'text',
+            analyzer: 'japanese',
+          },
+          en: {
+            type: 'text',
+            analyzer: 'english_edge_ngram',
+            search_analyzer: 'standard',
+          },
+        },
+      },
+      username: {
+        type: 'keyword',
+      },
+      comment_count: {
+        type: 'integer',
+      },
+      bookmark_count: {
+        type: 'integer',
+      },
+      like_count: {
+        type: 'integer',
+      },
+      grant: {
+        type: 'integer',
+      },
+      granted_users: {
+        type: 'keyword',
+      },
+      granted_groups: {
+        type: 'keyword',
+      },
+      created_at: {
+        type: 'date',
+        format: 'dateOptionalTime',
+      },
+      updated_at: {
+        type: 'date',
+        format: 'dateOptionalTime',
+      },
+      tag_names: {
+        type: 'keyword',
+      },
+    },
+  },
+};

+ 0 - 118
apps/app/resource/search/mappings-es8-for-ci.json

@@ -1,118 +0,0 @@
-{
-  "settings": {
-    "analysis": {
-      "filter": {
-        "english_stop": {
-          "type":       "stop",
-          "stopwords":  "_english_"
-        }
-      },
-      "tokenizer": {
-        "edge_ngram_tokenizer": {
-          "type": "edge_ngram",
-          "min_gram": 2,
-          "max_gram": 20,
-          "token_chars": ["letter", "digit"]
-        }
-      },
-      "analyzer": {
-        "japanese": {
-          "tokenizer": "edge_ngram_tokenizer",
-          "filter": [
-            "lowercase",
-            "english_stop"
-          ]
-        },
-        "english_edge_ngram": {
-          "tokenizer": "edge_ngram_tokenizer",
-          "filter": [
-            "lowercase",
-            "english_stop"
-          ]
-        }
-      }
-    }
-  },
-  "mappings": {
-    "properties" : {
-      "path": {
-        "type": "text",
-        "fields": {
-          "raw": {
-            "type": "text",
-            "analyzer": "keyword"
-          },
-          "ja": {
-            "type": "text",
-            "analyzer": "japanese"
-          },
-          "en": {
-            "type": "text",
-            "analyzer": "english_edge_ngram",
-            "search_analyzer": "standard"
-          }
-        }
-      },
-      "body": {
-        "type": "text",
-        "fields": {
-          "ja": {
-            "type": "text",
-            "analyzer": "japanese"
-          },
-          "en": {
-            "type": "text",
-            "analyzer": "english_edge_ngram",
-            "search_analyzer": "standard"
-          }
-        }
-      },
-      "comments": {
-        "type": "text",
-        "fields": {
-          "ja": {
-            "type": "text",
-            "analyzer": "japanese"
-          },
-          "en": {
-            "type": "text",
-            "analyzer": "english_edge_ngram",
-            "search_analyzer": "standard"
-          }
-        }
-      },
-      "username": {
-        "type": "keyword"
-      },
-      "comment_count": {
-        "type": "integer"
-      },
-      "bookmark_count": {
-        "type": "integer"
-      },
-      "like_count": {
-        "type": "integer"
-      },
-      "grant": {
-        "type": "integer"
-      },
-      "granted_users": {
-        "type": "keyword"
-      },
-      "granted_groups": {
-        "type": "keyword"
-      },
-      "created_at": {
-        "type": "date",
-        "format": "date_optional_time"
-      },
-      "updated_at": {
-        "type": "date",
-        "format": "date_optional_time"
-      },
-      "tag_names": {
-        "type": "keyword"
-      }
-    }
-  }
-}

+ 0 - 119
apps/app/resource/search/mappings-es8.json

@@ -1,119 +0,0 @@
-{
-  "settings": {
-    "analysis": {
-      "filter": {
-        "english_stop": {
-          "type":       "stop",
-          "stopwords":  "_english_"
-        }
-      },
-      "tokenizer": {
-        "edge_ngram_tokenizer": {
-          "type": "edge_ngram",
-          "min_gram": 2,
-          "max_gram": 20,
-          "token_chars": ["letter", "digit"]
-        }
-      },
-      "analyzer": {
-        "japanese": {
-          "tokenizer": "kuromoji_tokenizer",
-          "char_filter" : ["icu_normalizer"]
-        },
-        "english_edge_ngram": {
-          "tokenizer": "edge_ngram_tokenizer",
-          "filter": [
-            "lowercase",
-            "english_stop"
-          ]
-        }
-      }
-    }
-  },
-  "mappings": {
-    "properties" : {
-      "path": {
-        "type": "text",
-        "fields": {
-          "raw": {
-            "type": "text",
-            "analyzer": "keyword"
-          },
-          "ja": {
-            "type": "text",
-            "analyzer": "japanese"
-          },
-          "en": {
-            "type": "text",
-            "analyzer": "english_edge_ngram",
-            "search_analyzer": "standard"
-          }
-        }
-      },
-      "body": {
-        "type": "text",
-        "fields": {
-          "ja": {
-            "type": "text",
-            "analyzer": "japanese"
-          },
-          "en": {
-            "type": "text",
-            "analyzer": "english_edge_ngram",
-            "search_analyzer": "standard"
-          }
-        }
-      },
-      "body_embedded": {
-        "type": "dense_vector",
-        "dims": 768
-      },
-      "comments": {
-        "type": "text",
-        "fields": {
-          "ja": {
-            "type": "text",
-            "analyzer": "japanese"
-          },
-          "en": {
-            "type": "text",
-            "analyzer": "english_edge_ngram",
-            "search_analyzer": "standard"
-          }
-        }
-      },
-      "username": {
-        "type": "keyword"
-      },
-      "comment_count": {
-        "type": "integer"
-      },
-      "bookmark_count": {
-        "type": "integer"
-      },
-      "like_count": {
-        "type": "integer"
-      },
-      "grant": {
-        "type": "integer"
-      },
-      "granted_users": {
-        "type": "keyword"
-      },
-      "granted_groups": {
-        "type": "keyword"
-      },
-      "created_at": {
-        "type": "date",
-        "format": "date_optional_time"
-      },
-      "updated_at": {
-        "type": "date",
-        "format": "date_optional_time"
-      },
-      "tag_names": {
-        "type": "keyword"
-      }
-    }
-  }
-}

+ 128 - 0
apps/app/resource/search/mappings-es8.ts

@@ -0,0 +1,128 @@
+import type { estypes } from '@elastic/elasticsearch8';
+
+type Mappings = {
+  settings: estypes.IndicesCreateRequest['settings'];
+  mappings: estypes.IndicesCreateRequest['mappings'];
+}
+
+export const mappings: Mappings = {
+  settings: {
+    analysis: {
+      filter: {
+        english_stop: {
+          type:       'stop',
+          stopwords:  '_english_',
+        },
+      },
+      tokenizer: {
+        edge_ngram_tokenizer: {
+          type: 'edge_ngram',
+          min_gram: 2,
+          max_gram: 20,
+          token_chars: ['letter', 'digit'],
+        },
+      },
+      analyzer: {
+        japanese: {
+          type: 'custom',
+          tokenizer: 'kuromoji_tokenizer',
+          char_filter: ['icu_normalizer'],
+        },
+        english_edge_ngram: {
+          type: 'custom',
+          tokenizer: 'edge_ngram_tokenizer',
+          filter: [
+            'lowercase',
+            'english_stop',
+          ],
+        },
+      },
+    },
+  },
+  mappings: {
+    properties: {
+      path: {
+        type: 'text',
+        fields: {
+          raw: {
+            type: 'text',
+            analyzer: 'keyword',
+          },
+          ja: {
+            type: 'text',
+            analyzer: 'japanese',
+          },
+          en: {
+            type: 'text',
+            analyzer: 'english_edge_ngram',
+            search_analyzer: 'standard',
+          },
+        },
+      },
+      body: {
+        type: 'text',
+        fields: {
+          ja: {
+            type: 'text',
+            analyzer: 'japanese',
+          },
+          en: {
+            type: 'text',
+            analyzer: 'english_edge_ngram',
+            search_analyzer: 'standard',
+          },
+        },
+      },
+      body_embedded: {
+        type: 'dense_vector',
+        dims: 768,
+      },
+      comments: {
+        type: 'text',
+        fields: {
+          ja: {
+            type: 'text',
+            analyzer: 'japanese',
+          },
+          en: {
+            type: 'text',
+            analyzer: 'english_edge_ngram',
+            search_analyzer: 'standard',
+          },
+        },
+      },
+      username: {
+        type: 'keyword',
+      },
+      comment_count: {
+        type: 'integer',
+      },
+      bookmark_count: {
+        type: 'integer',
+      },
+      like_count: {
+        type: 'integer',
+      },
+      grant: {
+        type: 'integer',
+      },
+      granted_users: {
+        type: 'keyword',
+      },
+      granted_groups: {
+        type: 'keyword',
+      },
+      created_at: {
+        type: 'date',
+        format: 'date_optional_time',
+      },
+      updated_at: {
+        type: 'date',
+        format: 'date_optional_time',
+      },
+      tag_names: {
+        type: 'keyword',
+      },
+    },
+  },
+};

+ 127 - 0
apps/app/resource/search/mappings-es9-for-ci.ts

@@ -0,0 +1,127 @@
+import type { estypes } from '@elastic/elasticsearch9';
+
+type Mappings = {
+  settings: estypes.IndicesCreateRequest['settings'];
+  mappings: estypes.IndicesCreateRequest['mappings'];
+}
+
+export const mappings: Mappings = {
+  settings: {
+    analysis: {
+      filter: {
+        english_stop: {
+          type:       'stop',
+          stopwords:  '_english_',
+        },
+      },
+      tokenizer: {
+        edge_ngram_tokenizer: {
+          type: 'edge_ngram',
+          min_gram: 2,
+          max_gram: 20,
+          token_chars: ['letter', 'digit'],
+        },
+      },
+      analyzer: {
+        japanese: {
+          type: 'custom',
+          tokenizer: 'edge_ngram_tokenizer',
+          filter: [
+            'lowercase',
+            'english_stop',
+          ],
+        },
+        english_edge_ngram: {
+          type: 'custom',
+          tokenizer: 'edge_ngram_tokenizer',
+          filter: [
+            'lowercase',
+            'english_stop',
+          ],
+        },
+      },
+    },
+  },
+  mappings: {
+    properties: {
+      path: {
+        type: 'text',
+        fields: {
+          raw: {
+            type: 'text',
+            analyzer: 'keyword',
+          },
+          ja: {
+            type: 'text',
+            analyzer: 'japanese',
+          },
+          en: {
+            type: 'text',
+            analyzer: 'english_edge_ngram',
+            search_analyzer: 'standard',
+          },
+        },
+      },
+      body: {
+        type: 'text',
+        fields: {
+          ja: {
+            type: 'text',
+            analyzer: 'japanese',
+          },
+          en: {
+            type: 'text',
+            analyzer: 'english_edge_ngram',
+            search_analyzer: 'standard',
+          },
+        },
+      },
+      comments: {
+        type: 'text',
+        fields: {
+          ja: {
+            type: 'text',
+            analyzer: 'japanese',
+          },
+          en: {
+            type: 'text',
+            analyzer: 'english_edge_ngram',
+            search_analyzer: 'standard',
+          },
+        },
+      },
+      username: {
+        type: 'keyword',
+      },
+      comment_count: {
+        type: 'integer',
+      },
+      bookmark_count: {
+        type: 'integer',
+      },
+      like_count: {
+        type: 'integer',
+      },
+      grant: {
+        type: 'integer',
+      },
+      granted_users: {
+        type: 'keyword',
+      },
+      granted_groups: {
+        type: 'keyword',
+      },
+      created_at: {
+        type: 'date',
+        format: 'date_optional_time',
+      },
+      updated_at: {
+        type: 'date',
+        format: 'date_optional_time',
+      },
+      tag_names: {
+        type: 'keyword',
+      },
+    },
+  },
+};

+ 128 - 0
apps/app/resource/search/mappings-es9.ts

@@ -0,0 +1,128 @@
+import type { estypes } from '@elastic/elasticsearch9';
+
+type Mappings = {
+  settings: estypes.IndicesCreateRequest['settings'];
+  mappings: estypes.IndicesCreateRequest['mappings'];
+}
+
+export const mappings: Mappings = {
+  settings: {
+    analysis: {
+      filter: {
+        english_stop: {
+          type:       'stop',
+          stopwords:  '_english_',
+        },
+      },
+      tokenizer: {
+        edge_ngram_tokenizer: {
+          type: 'edge_ngram',
+          min_gram: 2,
+          max_gram: 20,
+          token_chars: ['letter', 'digit'],
+        },
+      },
+      analyzer: {
+        japanese: {
+          type: 'custom',
+          tokenizer: 'kuromoji_tokenizer',
+          char_filter: ['icu_normalizer'],
+        },
+        english_edge_ngram: {
+          type: 'custom',
+          tokenizer: 'edge_ngram_tokenizer',
+          filter: [
+            'lowercase',
+            'english_stop',
+          ],
+        },
+      },
+    },
+  },
+  mappings: {
+    properties: {
+      path: {
+        type: 'text',
+        fields: {
+          raw: {
+            type: 'text',
+            analyzer: 'keyword',
+          },
+          ja: {
+            type: 'text',
+            analyzer: 'japanese',
+          },
+          en: {
+            type: 'text',
+            analyzer: 'english_edge_ngram',
+            search_analyzer: 'standard',
+          },
+        },
+      },
+      body: {
+        type: 'text',
+        fields: {
+          ja: {
+            type: 'text',
+            analyzer: 'japanese',
+          },
+          en: {
+            type: 'text',
+            analyzer: 'english_edge_ngram',
+            search_analyzer: 'standard',
+          },
+        },
+      },
+      body_embedded: {
+        type: 'dense_vector',
+        dims: 768,
+      },
+      comments: {
+        type: 'text',
+        fields: {
+          ja: {
+            type: 'text',
+            analyzer: 'japanese',
+          },
+          en: {
+            type: 'text',
+            analyzer: 'english_edge_ngram',
+            search_analyzer: 'standard',
+          },
+        },
+      },
+      username: {
+        type: 'keyword',
+      },
+      comment_count: {
+        type: 'integer',
+      },
+      bookmark_count: {
+        type: 'integer',
+      },
+      like_count: {
+        type: 'integer',
+      },
+      grant: {
+        type: 'integer',
+      },
+      granted_users: {
+        type: 'keyword',
+      },
+      granted_groups: {
+        type: 'keyword',
+      },
+      created_at: {
+        type: 'date',
+        format: 'date_optional_time',
+      },
+      updated_at: {
+        type: 'date',
+        format: 'date_optional_time',
+      },
+      tag_names: {
+        type: 'keyword',
+      },
+    },
+  },
+};

+ 2 - 0
apps/app/src/server/service/search-delegator/elasticsearch-client-delegator/es7-client-delegator.ts

@@ -11,6 +11,8 @@ export class ES7ClientDelegator {
 
   private client: Client;
 
+  delegetorVersion = 7 as const;
+
   constructor(options: ClientOptions, rejectUnauthorized: boolean) {
     this.client = new Client({ ...options, ssl: { rejectUnauthorized } });
   }

+ 2 - 0
apps/app/src/server/service/search-delegator/elasticsearch-client-delegator/es8-client-delegator.ts

@@ -4,6 +4,8 @@ export class ES8ClientDelegator {
 
   private client: Client;
 
+  delegetorVersion = 8 as const;
+
   constructor(options: ClientOptions, rejectUnauthorized: boolean) {
     this.client = new Client({ ...options, tls: { rejectUnauthorized } });
   }

+ 2 - 0
apps/app/src/server/service/search-delegator/elasticsearch-client-delegator/es9-client-delegator.ts

@@ -4,6 +4,8 @@ export class ES9ClientDelegator {
 
   private client: Client;
 
+  delegetorVersion = 9 as const;
+
   constructor(options: ClientOptions, rejectUnauthorized: boolean) {
     this.client = new Client({ ...options, tls: { rejectUnauthorized } });
   }

+ 4 - 4
apps/app/src/server/service/search-delegator/elasticsearch-client-delegator/get-client.ts

@@ -5,7 +5,7 @@ import type { ClientOptions as ES9ClientOptions } from '@elastic/elasticsearch9'
 import { type ES7ClientDelegator } from './es7-client-delegator';
 import { type ES8ClientDelegator } from './es8-client-delegator';
 import { type ES9ClientDelegator } from './es9-client-delegator';
-import type { ElasticSEarchClientDeletegator } from './interfaces';
+import type { ElasticsearchClientDelegator } from './interfaces';
 
 type GetDelegatorOptions = {
   version: 7;
@@ -24,16 +24,16 @@ type GetDelegatorOptions = {
 type IsAny<T> = 'dummy' extends (T & 'dummy') ? true : false;
 type Delegator<Opts extends GetDelegatorOptions> =
   IsAny<Opts> extends true
-    ? ElasticSEarchClientDeletegator
+    ? ElasticsearchClientDelegator
     : Opts extends { version: 7 }
       ? ES7ClientDelegator
       : Opts extends { version: 8 }
         ? ES8ClientDelegator
         : Opts extends { version: 9 }
           ? ES9ClientDelegator
-          : ElasticSEarchClientDeletegator
+          : ElasticsearchClientDelegator
 
-let instance: ElasticSEarchClientDeletegator | null = null;
+let instance: ElasticsearchClientDelegator | null = null;
 export const getClient = async<Opts extends GetDelegatorOptions>(opts: Opts): Promise<Delegator<Opts>> => {
   if (instance == null) {
     if (opts.version === 7) {

+ 16 - 1
apps/app/src/server/service/search-delegator/elasticsearch-client-delegator/interfaces.ts

@@ -2,4 +2,19 @@ import type { ES7ClientDelegator } from './es7-client-delegator';
 import type { ES8ClientDelegator } from './es8-client-delegator';
 import type { ES9ClientDelegator } from './es9-client-delegator';
 
-export type ElasticSEarchClientDeletegator = ES7ClientDelegator | ES8ClientDelegator | ES9ClientDelegator;
+export type ElasticsearchClientDelegator = ES7ClientDelegator | ES8ClientDelegator | ES9ClientDelegator;
+
+
+// type guard
+export const isES7ClientDelegetor = (delegator: ElasticsearchClientDelegator): delegator is ES7ClientDelegator => {
+  return delegator.delegetorVersion === 7;
+};
+
+export const isES8ClientDelegetor = (delegator: ElasticsearchClientDelegator): delegator is ES8ClientDelegator => {
+  return delegator.delegetorVersion === 8;
+};
+
+// TODO: https://redmine.weseek.co.jp/issues/168446
+export const isES9ClientDelegetor = (delegator: ElasticsearchClientDelegator): delegator is ES9ClientDelegator => {
+  return delegator.delegetorVersion === 9;
+};

+ 31 - 12
apps/app/src/server/service/search-delegator/elasticsearch.ts

@@ -24,7 +24,9 @@ import type { UpdateOrInsertPagesOpts } from '../interfaces/search';
 
 import { aggregatePipelineToIndex } from './aggregate-to-index';
 import type { AggregatedPage, BulkWriteBody, BulkWriteCommand } from './bulk-write';
-import { getClient, type ElasticSEarchClientDeletegator } from './elasticsearch-client-delegator';
+import {
+  getClient, type ElasticsearchClientDelegator, isES9ClientDelegetor, isES7ClientDelegetor, isES8ClientDelegetor,
+} from './elasticsearch-client-delegator';
 
 const logger = loggerFactory('growi:service:search-delegator:elasticsearch');
 
@@ -61,7 +63,7 @@ class ElasticsearchDelegator implements SearchDelegator<Data, ESTermsKey, ESQuer
 
   private elasticsearchVersion: 7 | 8 | 9;
 
-  private client: ElasticSEarchClientDeletegator;
+  private client: ElasticsearchClientDelegator;
 
   private indexName: string;
 
@@ -314,19 +316,36 @@ class ElasticsearchDelegator implements SearchDelegator<Data, ESTermsKey, ESQuer
     }
   }
 
-  async createIndex(index) {
-    let mappings = this.isElasticsearchV7
-      ? require('^/resource/search/mappings-es7.json')
-      : require('^/resource/search/mappings-es8.json');
+  async createIndex(index: string) {
+    // TODO: https://redmine.weseek.co.jp/issues/168446
+    if (isES7ClientDelegetor(this.client)) {
+      const { mappings } = await import('^/resource/search/mappings-es7');
+      return this.client.indices.create({
+        index,
+        body: {
+          ...mappings,
+        },
+      });
+    }
 
-    if (process.env.CI) {
-      mappings = require('^/resource/search/mappings-es8-for-ci.json');
+    if (isES8ClientDelegetor(this.client)) {
+      const { mappings } = await import('^/resource/search/mappings-es8');
+      return this.client.indices.create({
+        index,
+        ...mappings,
+      });
     }
 
-    return this.client.indices.create({
-      index,
-      body: mappings,
-    });
+    if (isES9ClientDelegetor(this.client)) {
+      const { mappings } = process.env.CI == null
+        ? await import('^/resource/search/mappings-es9')
+        : await import('^/resource/search/mappings-es9-for-ci');
+
+      return this.client.indices.create({
+        index,
+        ...mappings,
+      });
+    }
   }
 
   /**