Просмотр исходного кода

Merge pull request #7862 from weseek/fix/124941

fix: Type safe implementation for objects imported from ElasticsearchClient
Yuki Takei 2 лет назад
Родитель
Сommit
c2d3dc09ff

+ 7 - 0
apps/app/src/interfaces/search.ts

@@ -21,6 +21,13 @@ export type ISearchResultMeta = {
   },
 }
 
+export type ISearchResultData = {
+  _id: string
+  _score: number
+  _source: any
+  _highlight: any
+}
+
 export type ISearchResult<T> = ISearchResultMeta & {
   data: T[],
 }

+ 11 - 7
apps/app/src/server/service/search-delegator/elasticsearch-client.ts

@@ -53,9 +53,9 @@ export default class ElasticsearchClient {
   };
 
   cluster = {
-    health: (params: ES7RequestParams.ClusterHealth & estypes.ClusterHealthRequest)
+    health: ()
     : Promise<ES7ApiResponse<ClusterHealthResponse> | estypes.ClusterHealthResponse> =>
-      this.client instanceof ES7Client ? this.client.cluster.health(params) : this.client.cluster.health(params),
+      this.client instanceof ES7Client ? this.client.cluster.health() : this.client.cluster.health(),
   };
 
   indices = {
@@ -71,9 +71,11 @@ export default class ElasticsearchClient {
     : Promise<IndicesExistsResponse | estypes.IndicesExistsResponse> =>
       this.client instanceof ES7Client ? (await this.client.indices.exists(params)).body as IndicesExistsResponse : this.client.indices.exists(params),
 
-    existsAlias: (params: ES7RequestParams.IndicesExistsAlias & estypes.IndicesExistsAliasRequest)
-    : Promise<ES7ApiResponse<IndicesExistsAliasResponse> | estypes.IndicesExistsAliasResponse> =>
-      this.client instanceof ES7Client ? this.client.indices.existsAlias(params) : this.client.indices.existsAlias(params),
+    existsAlias: async(params: ES7RequestParams.IndicesExistsAlias & estypes.IndicesExistsAliasRequest)
+    : Promise<IndicesExistsAliasResponse | estypes.IndicesExistsAliasResponse> =>
+      this.client instanceof ES7Client
+        ? (await this.client.indices.existsAlias(params)).body as IndicesExistsAliasResponse
+        : this.client.indices.existsAlias(params),
 
     // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
     putAlias: (params: ES7RequestParams.IndicesPutAlias & estypes.IndicesPutAliasRequest) =>
@@ -107,8 +109,10 @@ export default class ElasticsearchClient {
     return this.client instanceof ES7Client ? this.client.ping() : this.client.ping();
   }
 
-  reindex(params: ES7RequestParams.Reindex & estypes.ReindexRequest): Promise<ES7ApiResponse<ReindexResponse> | estypes.ReindexResponse> {
-    return this.client instanceof ES7Client ? this.client.reindex(params) : this.client.reindex(params);
+  reindex(indexName: string, tmpIndexName: string): Promise<ES7ApiResponse<ReindexResponse> | estypes.ReindexResponse> {
+    return this.client instanceof ES7Client
+      ? this.client.reindex({ wait_for_completion: false, body: { source: { index: indexName }, dest: { index: tmpIndexName } } })
+      : this.client.reindex({ wait_for_completion: false, source: { index: indexName }, dest: { index: tmpIndexName } });
   }
 
   async search(params: ES7RequestParams.Search & estypes.SearchRequest): Promise<SearchResponse | estypes.SearchResponse> {

+ 15 - 24
apps/app/src/server/service/search-delegator/elasticsearch.ts

@@ -7,7 +7,7 @@ import streamToPromise from 'stream-to-promise';
 
 import { SearchDelegatorName } from '~/interfaces/named-query';
 import {
-  IFormattedSearchResult, ISearchResult, SORT_AXIS, SORT_ORDER,
+  ISearchResult, ISearchResultData, SORT_AXIS, SORT_ORDER,
 } from '~/interfaces/search';
 import loggerFactory from '~/utils/logger';
 
@@ -58,7 +58,7 @@ class ElasticsearchDelegator implements SearchDelegator<Data, ESTermsKey, ESQuer
 
   elasticsearch: any;
 
-  client: any;
+  client: ElasticsearchClient;
 
   queries: any;
 
@@ -80,7 +80,6 @@ class ElasticsearchDelegator implements SearchDelegator<Data, ESTermsKey, ESQuer
     this.isElasticsearchV7 = elasticsearchVersion === 7;
 
     this.isElasticsearchReindexOnBoot = this.configManager.getConfig('crowi', 'app:elasticsearchReindexOnBoot');
-    this.client = null;
 
     // In Elasticsearch RegExp, we don't need to used ^ and $.
     // Ref: https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-regexp-query.html#_standard_operators
@@ -184,14 +183,14 @@ class ElasticsearchDelegator implements SearchDelegator<Data, ESTermsKey, ESQuer
    */
   async getInfo() {
     const info = await this.client.nodes.info();
-    if (!info._nodes || !info.nodes) {
+    if (!info != null) {
       throw new Error('There is no nodes');
     }
 
     let esVersion = 'unknown';
     const esNodeInfos = {};
 
-    for (const [nodeName, nodeInfo] of Object.entries<any>(info.nodes)) {
+    for (const [nodeName, nodeInfo] of Object.entries<any>(info)) {
       esVersion = nodeInfo.version;
 
       const filteredInfo = {
@@ -275,24 +274,10 @@ class ElasticsearchDelegator implements SearchDelegator<Data, ESTermsKey, ESQuer
 
     const tmpIndexName = `${indexName}-tmp`;
 
-    const reindexRequest = this.isElasticsearchV7
-      ? {
-        waitForCompletion: false,
-        body: {
-          source: { index: indexName },
-          dest: { index: tmpIndexName },
-        },
-      }
-      : {
-        wait_for_completion: false,
-        source: { index: indexName },
-        dest: { index: tmpIndexName },
-      };
-
     try {
       // reindex to tmp index
       await this.createIndex(tmpIndexName);
-      await client.reindex(reindexRequest);
+      await client.reindex(indexName, tmpIndexName);
 
       // update alias
       await client.indices.updateAliases({
@@ -345,7 +330,7 @@ class ElasticsearchDelegator implements SearchDelegator<Data, ESTermsKey, ESQuer
     }
 
     // create alias
-    const { body: isExistsAlias } = await client.indices.existsAlias({ name: aliasName, index: indexName });
+    const isExistsAlias = await client.indices.existsAlias({ name: aliasName, index: indexName });
     if (!isExistsAlias) {
       await client.indices.putAlias({
         name: aliasName,
@@ -653,7 +638,7 @@ class ElasticsearchDelegator implements SearchDelegator<Data, ESTermsKey, ESQuer
    *   data: [ pages ...],
    * }
    */
-  async searchKeyword(query): Promise<IFormattedSearchResult> {
+  async searchKeyword(query): Promise<ISearchResult<ISearchResultData>> {
 
     // for debug
     if (process.env.NODE_ENV === 'development') {
@@ -674,10 +659,16 @@ class ElasticsearchDelegator implements SearchDelegator<Data, ESTermsKey, ESQuer
 
     const searchResponse = await this.client.search(query);
 
+    const _total = searchResponse?.hits?.total;
+    let total = 0;
+    if (typeof _total === 'object') {
+      total = _total.value;
+    }
+
     return {
       meta: {
+        total,
         took: searchResponse.took,
-        total: searchResponse.hits.total.value,
         hitsCount: searchResponse.hits.hits.length,
       },
       data: searchResponse.hits.hits.map((elm) => {
@@ -944,7 +935,7 @@ class ElasticsearchDelegator implements SearchDelegator<Data, ESTermsKey, ESQuer
     };
   }
 
-  async search(data: SearchableData<ESQueryTerms>, user, userGroups, option?): Promise<ISearchResult<unknown>> {
+  async search(data: SearchableData<ESQueryTerms>, user, userGroups, option?): Promise<ISearchResult<ISearchResultData>> {
     const { queryString, terms } = data;
 
     if (terms == null) {