Skip to content

Commit

Permalink
Modified query request and response models
Browse files Browse the repository at this point in the history
  • Loading branch information
sahalali committed Jul 4, 2024
1 parent 2dc9a73 commit e3756bf
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 63 deletions.
31 changes: 16 additions & 15 deletions src/constant/recon-queries.constants.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
export const QUERIES = {

RECONCILITAION_QUERY:`
RECONCILITAION_QUERY: `
PREFIX luc: <http://www.ontotext.com/connectors/lucene#>
PREFIX luc-index: <http://www.ontotext.com/connectors/lucene/instance#>
PREFIX schema: <http://schema.org/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX ado: <http://kg.artsdata.ca/ontology/>
PREFIX onto: <http://www.ontotext.com/>
SELECT DISTINCT
?entity
?score
(SAMPLE(?name_en) as ?nameEn)
(SAMPLE(?name_fr) as ?nameFr)
(SAMPLE(?name_no) as ?name)
?type
?type_label
(SAMPLE(?description_no) as ?description)
(SAMPLE(?description_en) as ?descriptionEn)
(SAMPLE(?description_fr) as ?descriptionFr)
(SAMPLE(?description_no) as ?description)
(SAMPLE(?description_en) as ?descriptionEn)
(SAMPLE(?description_fr) as ?descriptionFr)
?type_label
?type
WHERE
{
values ?query { "QUERY_PLACE_HOLDER" }
Expand All @@ -29,23 +30,23 @@ WHERE
luc:entities ?entity .
FILTER (CONTAINS(STR(?entity),"kg.artsdata.ca/resource/"))
?entity luc:score ?score.
?entity luc:score ?score;
# a ?type_additional.
#NAME
OPTIONAL { ?entity rdfs:label ?name_en. FILTER( LANG(?name_en) = "en") }
OPTIONAL { ?entity rdfs:label ?name_fr. FILTER( LANG(?name_fr) = "fr")}
OPTIONAL { ?entity rdfs:label ?name_no. FILTER ( LANG(?name_no) = "")}
#NAME
OPTIONAL { ?entity schema:name ?name_en. FILTER( LANG(?name_en) = "en") }
OPTIONAL { ?entity schema:name ?name_fr. FILTER( LANG(?name_fr) = "fr")}
OPTIONAL { ?entity schema:name ?name_no. FILTER ( LANG(?name_no) = "")}
#TYPE
#TYPE
OPTIONAL { ?type rdfs:label ?type_label_raw filter(lang(?type_label_raw) = "") }
OPTIONAL { ?type rdfs:label ?type_label_en filter(lang(?type_label_en) = "en") }
BIND(COALESCE(?type_label_en, ?type_label_raw, "") as ?type_label)
# DISAMBIGUATING DESCRIPTION
#DISAMBIGUATING DESCRIPTION
OPTIONAL { ?entity schema:disambiguatingDescription ?description_en. FILTER( LANG(?description_en) = "en") }
OPTIONAL { ?entity schema:disambiguatingDescription ?description_fr. FILTER( LANG(?description_fr) = "fr")}
OPTIONAL { ?entity schema:disambiguatingDescription ?description_no. FILTER ( LANG(?description_no) = "")}
} group by ?entity ?score ?name_en ?name_fr ?name_no ?type ?type_label ?description_en ?description_fr ?description_no
} group by ?entity ?score ?type_label ?type
`
};
12 changes: 5 additions & 7 deletions src/controller/recon/recon.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Body, Controller, Get, Post, Query } from "@nestjs/common";
import { ApiBody, ApiOperation, ApiQuery, ApiResponse, ApiTags } from "@nestjs/swagger";
import { ReconciliationResponse } from "../../dto";
import { ApiOperation, ApiQuery, ApiResponse, ApiTags } from "@nestjs/swagger";
import { ReconciliationRequest, ReconciliationResponse } from "../../dto";
import { ReconciliationService } from "../../service";

@Controller()
Expand All @@ -17,7 +17,8 @@ export class ReconciliationController {
name: "queries",
description: "Queries",
required: false,
explode: false
explode: false,
example: "{\"queries\":{\"conditions\":[{\"matchType\":\"string\",\"v\":\"string\"}]}}"
})
async reconcileByQuery(
@Query("queries") rawQueries: string
Expand All @@ -29,10 +30,7 @@ export class ReconciliationController {
@ApiOperation({ summary: "Reconcile" })
@ApiResponse({ status: 200, type: ReconciliationResponse, isArray: true, description: "Reconciliation response" })
@ApiResponse({ status: 500, description: "Internal server error" })
@ApiBody({})


async reconcileByQueries(@Body() reconciliationRequest: any): Promise<ReconciliationResponse[]> {
async reconcileByQueries(@Body() reconciliationRequest: ReconciliationRequest): Promise<ReconciliationResponse> {
return await this._reconciliationService.reconcileByQueries(reconciliationRequest);
}

Expand Down
44 changes: 34 additions & 10 deletions src/dto/recon.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,54 @@ export class MultilingualValues {
lang?: string;
}

class MultilingualString {
class MultilingualString {
@ApiProperty({ type: [MultilingualValues] })
values: MultilingualValues[];
}

export class ReconciliationResponse {
export class ResultCandidates {
@ApiProperty()
id: string;
@ApiProperty({ type: [MultilingualString] })
name: MultilingualString;
@ApiProperty({ type: [MultilingualString] })
description: MultilingualString;
@ApiProperty({ type: [ReconciliationType] })
type: ReconciliationType[];
@ApiProperty()
name: MultilingualString | string;
@ApiProperty()
description: MultilingualString | string;
@ApiProperty()
score: number;
@ApiProperty()
match: boolean;
@ApiProperty({ type: [ReconciliationType] })
type: ReconciliationType[];
}

export class ReconciliationQuery {
export class ReconciliationResults {
@ApiProperty()
query: string;
candidates: ResultCandidates[];
}

export class ReconciliationResponse {
@ApiProperty({ type: ReconciliationResults })
results: ReconciliationResults[];
}


class QueryCondition {
@ApiProperty()
matchType: string;
@ApiProperty()
v: string;
}

class ReconciliationQuery {
@ApiProperty()
type: string;
@ApiProperty()
limit: number;
@ApiProperty({ type: [QueryCondition] })
conditions: QueryCondition[];
}

export class ReconciliationRequest {
@ApiProperty({ type: [ReconciliationQuery] })
queries: ReconciliationQuery[];
}
2 changes: 0 additions & 2 deletions src/enum/index.ts

This file was deleted.

30 changes: 20 additions & 10 deletions src/helper/reconciliation-service.helper.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { MultilingualValues, ReconciliationResponse } from "../dto";
import { MultilingualValues, ReconciliationResults, ResultCandidates } from "../dto";
import { LanguageTagEnum } from "../enum";
import { GRAPHDB_INDEX } from "../config";

export class ReconciliationServiceHelper {

static formatReconciliationResponse(query: string, sparqlResponse: any): ReconciliationResponse[] {
static formatReconciliationResponse(query: string, sparqlResponse: any) {

return sparqlResponse?.results?.bindings?.map((binding: any) => {
const nameValues: MultilingualValues[] = [];
const descriptionValues: MultilingualValues[] = [];

const result = new ReconciliationResponse();
const resultCandidate = new ResultCandidates();
const uri = binding["entity"].value;
result.id = uri?.split("http://kg.artsdata.ca/resource/").pop();
resultCandidate.id = uri?.split("http://kg.artsdata.ca/resource/").pop();

//NAME
const name = binding["name"]?.value;
Expand All @@ -27,7 +27,7 @@ export class ReconciliationServiceHelper {
if (name && !nameEn || !nameFr) {
nameValues.push({ str: name });
}
result.name = { values: nameValues };
resultCandidate.name = { values: nameValues };

//DESCRIPTION
const description = binding["description"]?.value;
Expand All @@ -42,15 +42,25 @@ export class ReconciliationServiceHelper {
if (description && !descriptionEn && !descriptionFr) {
descriptionValues.push({ str: description });
}
result.description = { values: descriptionValues };
resultCandidate.description = { values: descriptionValues };

//SCORE
result.score = binding["score"]?.value;
resultCandidate.score = binding["score"]?.value;

//TODO match is incorrect when query contains accented characters
result.match = binding["name"]?.value.toLowerCase() === query.toLowerCase();
result.type = [{ id: binding["type"]?.value, name: binding["type_label"]?.value }];
return result;
resultCandidate.match = binding["name"]?.value.toLowerCase() === query.toLowerCase();
const typeUris = binding["type"]?.value.split("|");
const typeLabels = binding["type_label"]?.value.split("|");
const resultType: { id: string; name: string; }[] = [];
if (typeUris?.length > 1) {
for (let i = 0; typeUris?.length > i; i++) {
resultType.push({ id: typeUris[i], name: typeLabels[i] });
}
} else {
resultType.push({ id: typeUris[0], name: typeLabels[0] });
}
resultCandidate.type = resultType;
return resultCandidate ;
});

}
Expand Down
7 changes: 3 additions & 4 deletions src/service/artsdata/artsdata.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { ARTSDATA } from "../../config";
import { QUERIES } from "../../constant/recon-queries.constants";
import { HttpService } from "../http";
import { ReconciliationServiceHelper } from "../../helper/reconciliation-service.helper";
import { ReconciliationResponse } from "../../dto";

@Injectable()
export class ArtsdataService {
Expand All @@ -12,12 +11,12 @@ export class ArtsdataService {
}

_getArtsdataEndPoint(): string {
const route = "repositories/"+ARTSDATA.REPOSITORY
const route = "repositories/" + ARTSDATA.REPOSITORY;
const sparqlEndpoint = new URL(route, ARTSDATA.ENDPOINT);
return sparqlEndpoint.toString();
}

async getReconciliationResult(name: string, type: string, limit?: number): Promise<ReconciliationResponse[]> {
async getReconciliationResult(name: string, type: string, limit?: number) {
if (name === undefined || name === null || name === "") {
return [];
}
Expand All @@ -32,7 +31,7 @@ export class ArtsdataService {
}
const sparqlQuery = "query=" + encodeURIComponent(rawSparqlQuery);
const response = await this.httpService.postRequest(sparqlEndpoint, sparqlQuery);
return ReconciliationServiceHelper.formatReconciliationResponse(name,response);
return ReconciliationServiceHelper.formatReconciliationResponse(name, response);
}


Expand Down
31 changes: 16 additions & 15 deletions src/service/recon/recon.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Injectable } from "@nestjs/common";
import { ArtsdataService } from "../artsdata";
import { ManifestService } from "../manifest";
import { ReconciliationResponse } from "../../dto";
import { ReconciliationRequest, ReconciliationResponse, ReconciliationResults } from "../../dto";
import { Exception } from "../../helper";
import { ReconRequestMatchTypeEnum } from "../../enum";

@Injectable()
export class ReconciliationService {
Expand All @@ -25,21 +26,21 @@ export class ReconciliationService {
return await this.reconcileByQueries(queries);
}

async reconcileByQueries(queries: any): Promise<any> {
let index = 0;
const results: any = {};
while (true) {
const queryIndex: string = "q" + index;
const query = queries[queryIndex];
if (!query) {
break;
}
const result: ReconciliationResponse[] =
await this._artsdataService.getReconciliationResult(query.query, query.type, query.limit);
results["q" + index] = { result: result };
index++;
async reconcileByQueries(reconciliationRequest: ReconciliationRequest): Promise<ReconciliationResponse> {

const { queries } = reconciliationRequest;
const results: ReconciliationResults[] = [];
if (!queries) {
return { results: [] };
}
for (const reconciliationQuery of queries) {
const { type, limit, conditions } = reconciliationQuery;
const query = conditions
.find(condition => condition.matchType == ReconRequestMatchTypeEnum.NAME)?.v;
const candidates = await this._artsdataService.getReconciliationResult(query as string, type, limit);
results.push({ candidates: candidates });
}
return results;
return { results };
}

}

0 comments on commit e3756bf

Please sign in to comment.