Files
2022-12-07 04:43:36 +01:00

245 lines
7.3 KiB
JavaScript

const debug = require('debug')('termPortal:models/search-engine')
const { Client } = require('@opensearch-project/opensearch')
const ENTRY_INDEX = 'entry'
const CONSULTANCY_ENTRY_INDEX = 'consultancy_entry'
const client = new Client({ node: 'http://opensearch:9200' })
exports.initEntryIndex = async () => {
const { statusCode } = await client.indices.exists({ index: ENTRY_INDEX })
const doesIndexExist = statusCode === 200
if (doesIndexExist) {
debug('Entry search index already exists.')
return
}
await client.indices.create({
index: ENTRY_INDEX,
body: {
settings: {
number_of_replicas: 0
},
mappings: {
dynamic: 'strict',
properties: {
id: { type: 'keyword', index: false, doc_values: false },
isValid: { type: 'boolean', doc_values: false },
isPublished: { type: 'boolean', doc_values: false },
isTerminologyReviewed: { type: 'boolean', doc_values: false },
isLanguageReviewed: { type: 'boolean', doc_values: false },
status: { type: 'keyword', doc_values: false },
term: {
type: 'text',
doc_values: false,
fields: {
keyword: { type: 'keyword', doc_values: false },
sort: {
type: 'icu_collation_keyword',
index: false,
language: 'sl',
country: 'SI'
}
}
},
homonymSort: { type: 'keyword', index: false },
label: { type: 'text', doc_values: false },
definition: { type: 'text', doc_values: false },
synonyms: { type: 'text', doc_values: false },
other: { type: 'text', doc_values: false },
timeMostRecentComment: { type: 'date' },
domainLabels: { type: 'text', doc_values: false },
links: { type: 'text', doc_values: false },
foreignEntries: {
type: 'nested',
properties: {
lang: {
properties: {
id: { type: 'keyword' },
code: { type: 'keyword', index: false, doc_values: false },
nameSl: { type: 'keyword', index: false, doc_values: false },
nameEn: { type: 'keyword', index: false, doc_values: false }
}
},
terms: {
type: 'text',
doc_values: false,
fields: {
keyword: { type: 'keyword', doc_values: false }
}
},
definition: { type: 'text', doc_values: false },
synonyms: { type: 'text', doc_values: false }
}
},
primaryDomain: {
properties: {
id: { type: 'keyword' },
nameSl: { type: 'keyword', index: false, doc_values: false },
nameEn: { type: 'keyword', index: false, doc_values: false }
}
},
dictionary: {
properties: {
id: { type: 'keyword' },
nameSl: { type: 'keyword', index: false, doc_values: false },
nameSlShort: { type: 'keyword', index: false, doc_values: false },
nameEn: { type: 'keyword', index: false, doc_values: false },
status: { type: 'keyword', doc_values: false }
}
},
source: {
properties: {
code: { type: 'keyword' },
name: { type: 'keyword', index: false, doc_values: false }
}
}
}
}
}
})
debug('Entry search index created.')
}
exports.initConsultancyEntryIndex = async () => {
const { statusCode } = await client.indices.exists({
index: CONSULTANCY_ENTRY_INDEX
})
const doesIndexExist = statusCode === 200
if (doesIndexExist) {
debug('Consultancy entry search index already exists.')
return
}
await client.indices.create({
index: CONSULTANCY_ENTRY_INDEX,
body: {
settings: {
number_of_replicas: 0
},
mappings: {
dynamic: 'strict',
properties: {
id: { type: 'keyword', index: false, doc_values: false },
timeCreated: { type: 'date', index: false },
status: { type: 'keyword', doc_values: false },
description: { type: 'text', index: false, doc_values: false },
title: { type: 'text', doc_values: false },
question: { type: 'text', doc_values: false },
answer: { type: 'text', doc_values: false },
answerAuthors: { type: 'keyword', index: false, doc_values: false },
primaryDomain: {
properties: {
id: { type: 'keyword', doc_values: false },
nameSl: { type: 'keyword', index: false, doc_values: false },
nameEn: { type: 'keyword', index: false, doc_values: false }
}
},
assignedConsultants: {
properties: {
id: { type: 'keyword', doc_values: false },
firstName: { type: 'keyword', index: false, doc_values: false },
lastName: { type: 'keyword', index: false, doc_values: false },
isModerator: { type: 'boolean', index: false, doc_values: false }
}
}
}
}
}
})
debug('Consultancy entry search index created.')
}
exports.waitForConnection = () => {
return new Promise(resolve => {
async function testConnection() {
try {
// eslint-disable-next-line no-console
console.log('Verifying connection to search engine server')
await client.ping()
// eslint-disable-next-line no-console
console.log('Connection to search engine server verified')
resolve()
} catch {
// eslint-disable-next-line no-console
console.error('Could not connect to search engine server')
setTimeout(testConnection, 1000)
}
}
testConnection()
})
}
exports.searchEngineClient = client
exports.ENTRY_INDEX = ENTRY_INDEX
exports.CONSULTANCY_ENTRY_INDEX = CONSULTANCY_ENTRY_INDEX
// A wrapper, to simplify querying the entry index.
exports.searchEntryIndex = async query => {
const hits = await client.search({
index: ENTRY_INDEX,
filter_path: 'hits,aggregations',
body: query
})
return hits
}
// A wrapper, to simplify querying the consultancy entry index.
exports.searchConsultancyEntryIndex = async query => {
const hits = await client.search({
index: CONSULTANCY_ENTRY_INDEX,
filter_path: 'hits',
body: query
})
return hits
}
exports.deleteEntryFromIndex = async (entryId, shouldWait) => {
await client.delete({
index: ENTRY_INDEX,
id: entryId,
refresh: shouldWait ? 'wait_for' : false
})
}
exports.deleteConsultancyEntryFromIndex = async (entryId, shouldWait) => {
await client.delete({
index: CONSULTANCY_ENTRY_INDEX,
id: entryId,
refresh: shouldWait ? 'wait_for' : false
})
}
exports.deleteDictionaryEntriesFromIndex = async dictionaryId => {
await client.deleteByQuery({
index: ENTRY_INDEX,
body: {
query: {
term: {
'dictionary.id': {
value: dictionaryId
}
}
}
}
})
}
exports.deleteConsultancyEntriesFromIndex = async () => {
await client.deleteByQuery({
index: CONSULTANCY_ENTRY_INDEX,
body: {
query: {
match_all: {}
}
}
})
}