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