Skip to content

Commit

Permalink
fix: Remove unnecessary properties from datasetMappings and add new m…
Browse files Browse the repository at this point in the history
…apping for scientificMetadata query
  • Loading branch information
Junjiequan committed Jul 19, 2024
1 parent 0b463dd commit 53f3710
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 55 deletions.
2 changes: 1 addition & 1 deletion src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ export const mapScientificQuery = (
const scientificFilterQueryOr: Record<string, unknown>[] = [];

const keyToFieldMapping: Record<string, string> = {
scientificMetadata: "scientificMetadata",
scientific: "scientificMetadata",
characteristics: "sampleCharacteristics",
};
Expand Down Expand Up @@ -180,6 +179,7 @@ export const mapScientificQuery = (
} else if (scientificFilterQueryOr.length > 1) {
scientificFilterQuery["$and"] = scientificFilterQueryOr;
}

return scientificFilterQuery;
};

Expand Down
10 changes: 1 addition & 9 deletions src/elastic-search/configuration/datasetFieldMapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,7 @@ export const datasetMappings: MappingObject = {
scientificMetadata: {
type: "nested",
dynamic: true,
properties: {
runNumber: {
properties: {
value: {
type: "long",
},
},
},
},
properties: {},
},
history: {
type: "nested",
Expand Down
16 changes: 14 additions & 2 deletions src/elastic-search/configuration/indexSetting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,25 @@ export const dynamic_template: Record<string, MappingDynamicTemplate>[] = [
},
},
},
{
double_as_double: {
path_match: "scientificMetadata.*.*",
match_mapping_type: "double",
mapping: {
type: "double",
coerce: true,
ignore_malformed: true,
},
},
},
{
date_as_keyword: {
path_match: "scientificMetadata.*.*",
match_mapping_type: "date",
mapping: {
type: "keyword",
ignore_above: 256,
type: "date",
format: "strict_date_optional_time||epoch_millis",
ignore_malformed: true,
},
},
},
Expand Down
4 changes: 2 additions & 2 deletions src/elastic-search/elastic-search.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ import {
import { ConfigService } from "@nestjs/config";
import { sleep } from "src/common/utils";
import {
transformKeysInObject,
initialSyncTransform,
transformFacets,
addValueType,
} from "./helpers/utils";

import { SortFields } from "./providers/fields.enum";
Expand Down Expand Up @@ -362,7 +362,7 @@ export class ElasticSearchService implements OnModuleInit {
async updateInsertDocument(data: Partial<DatasetDocument>) {
//NOTE: Replace all keys with lower case, also replace spaces and dot with underscore
delete data._id;
const transformedScientificMetadata = transformKeysInObject(
const transformedScientificMetadata = addValueType(
data.scientificMetadata as Record<string, unknown>,
);

Expand Down
136 changes: 95 additions & 41 deletions src/elastic-search/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,24 @@ import {
AggregationsFrequentItemSetsBucketKeys,
} from "@elastic/elasticsearch/lib/api/types";
import { DatasetClass } from "src/datasets/schemas/dataset.schema";
import { IFilter, ITransformedFullFacets } from "../interfaces/es-common.type";
import {
IFilter,
IQuery,
ITransformedFullFacets,
} from "../interfaces/es-common.type";

export const transformKey = (key: string): string => {
return key.trim().replace(/[.]/g, "\\.").replace(/ /g, "_").toLowerCase();
};
export const transformKeysInObject = (obj: Record<string, unknown>) => {
export const addValueType = (obj: Record<string, unknown>) => {
const newObj: Record<string, unknown> = {};

for (const [key, value] of Object.entries(obj)) {
const newKey = transformKey(key);

const isNumberValueType =
typeof (value as Record<string, unknown>)?.value === "number";

if (isNumberValueType) {
(value as Record<string, unknown>)["value_type"] = "number";
} else {
Expand Down Expand Up @@ -66,51 +71,100 @@ export const initialSyncTransform = (obj: DatasetClass) => {
return modifiedDocInObject;
};

export const convertToElasticSearchQuery = (
scientificQuery: Record<string, unknown>,
) => {
const extractNestedQueryOperationValue = (query: IQuery) => {
const field = Object.keys(query)[0];
const operationWithPrefix = Object.keys(query[field])[0];

const value =
typeof query[field][operationWithPrefix] === "string"
? (query[field][operationWithPrefix] as string).trim()
: query[field][operationWithPrefix];

const operation = operationWithPrefix.replace("$", "");

return { operation, value, field };
};

export const convertToElasticSearchQuery = (scientificQuery: any) => {

Check failure on line 88 in src/elastic-search/helpers/utils.ts

View workflow job for this annotation

GitHub Actions / eslint

Unexpected any. Specify a different type
const filters: IFilter[] = [];

for (const field in scientificQuery) {
const query = scientificQuery[field] as Record<string, unknown>;
const operation = Object.keys(query)[0];
const value =
typeof query[operation] === "string"
? (query[operation] as string).trim()
: query[operation];

const esOperation = operation.replace("$", "");

// NOTE-EXAMPLE:
// trasnformedKey = "scientificMetadata.someKey.value"
// firstPart = "scientificMetadata",
// middlePart = "someKey"
const { transformedKey, firstPart, middlePart } = transformMiddleKey(field);

let filter = {};

const fieldType = field.split(".").pop();

if (fieldType === "valueSI" || fieldType === "value") {
const numberFilter = {
term: {
[`${firstPart}.${middlePart}.value_type`]:
typeof value === "number" ? "number" : "string",
const query = scientificQuery[field] as any;

Check failure on line 92 in src/elastic-search/helpers/utils.ts

View workflow job for this annotation

GitHub Actions / eslint

Unexpected any. Specify a different type

if (field === "$and") {
query.forEach((query: any) => {

Check failure on line 95 in src/elastic-search/helpers/utils.ts

View workflow job for this annotation

GitHub Actions / eslint

Unexpected any. Specify a different type
const shouldQueries = query.$or.map((orQuery: any) => {

Check failure on line 96 in src/elastic-search/helpers/utils.ts

View workflow job for this annotation

GitHub Actions / eslint

Unexpected any. Specify a different type
const { operation, value, field } =
extractNestedQueryOperationValue(orQuery);
const filterType = operation === "eq" ? "term" : "range";
return {
[filterType]: {
[field]: operation === "eq" ? value : { [operation]: value },
},
};
});
filters.push({
bool: {
should: shouldQueries,
minimum_should_match: 1,
},
});
});
} else if (field === "$or") {
const shouldQueries = query.map((query: any) => {

Check failure on line 114 in src/elastic-search/helpers/utils.ts

View workflow job for this annotation

GitHub Actions / eslint

Unexpected any. Specify a different type
const { operation, value, field } =
extractNestedQueryOperationValue(query);
const filterType = operation === "eq" ? "term" : "range";
return {
[filterType]: {
[field]: operation === "eq" ? value : { [operation]: value },
},
};
});
filters.push({
bool: {
should: shouldQueries,
minimum_should_match: 1,
},
};
filters.push(numberFilter);
});
} else {
const operation = Object.keys(query)[0];
const value =
typeof query[operation] === "string"
? (query[operation] as string).trim()
: query[operation];
const esOperation = operation.replace("$", "");

// NOTE:
// trasnformedKey = "scientificMetadata.someKey.value"
// firstPart = "scientificMetadata",
// middlePart = "someKey"
// lastPart = "value"
const { transformedKey, firstPart, middlePart, lastPart } =
transformMiddleKey(field);

if (lastPart === "valueSI" || lastPart === "value") {
const numberFilter = {
term: {
[`${firstPart}.${middlePart}.value_type`]:
typeof value === "number" ? "number" : "string",
},
};
filters.push(numberFilter);
}

const filter =
esOperation === "eq"
? {
term: { [`${transformedKey}`]: value },
}
: {
range: { [`${transformedKey}`]: { [esOperation]: value } },
};

filters.push(filter);
}

filter =
esOperation === "eq"
? {
term: { [`${transformedKey}`]: value },
}
: { range: { [`${transformedKey}`]: { [esOperation]: value } } };

filters.push(filter);
}

return filters;
};

Expand Down
15 changes: 15 additions & 0 deletions src/elastic-search/interfaces/es-common.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ export interface IShould {
term?: {
[key: string]: string | undefined;
};
range?: {
[key: string]: {
gte?: string | number;
lte?: string | number;
};
};
}

export interface IBoolShould {
Expand Down Expand Up @@ -56,6 +62,10 @@ export interface IFilter {
};
};
};
bool?: {
should: IShould[];
minimum_should_match?: number;
};
}

export interface IFullFacets {
Expand All @@ -81,3 +91,8 @@ export interface ITransformedFullFacets {
}
| { totalSets: number };
}

type Operation = "$eq" | "$neq" | "$gte" | "$gt" | "$lte" | "$lt";

Check warning on line 95 in src/elastic-search/interfaces/es-common.type.ts

View workflow job for this annotation

GitHub Actions / eslint

'Operation' is defined but never used
export interface IQuery {
[key: string]: any;

Check failure on line 97 in src/elastic-search/interfaces/es-common.type.ts

View workflow job for this annotation

GitHub Actions / eslint

Unexpected any. Specify a different type
}

0 comments on commit 53f3710

Please sign in to comment.