Searching.ton
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
2.9 KiB

2 years ago
import { Client } from "@elastic/elasticsearch"
import { SEARCH_PER_PAGE } from "../../commonConstants"
import { detectLang, Languages } from "../../helpers/detectLang"
const INDEX_NAME = "common-website-test"
const RU_INDEX_NAME = "ru-website-test"
export interface ElasticIndexParams {
url: string
title: string
h1?: string
bodyText: string
description?: string
}
export interface ElasticSearchParams {
text: string
page?: number
}
const getIndexNameByLang = (lang: Languages) => {
switch (lang) {
case Languages.EN:
return INDEX_NAME
case Languages.RU:
return RU_INDEX_NAME
}
}
const getAnalyzerByLang = (lang: Languages) => {
switch (lang) {
case Languages.EN:
return undefined
case Languages.RU:
return "russian"
}
}
const getIndexNameByText = (text: string) => {
const lang = detectLang(text)
return getIndexNameByLang(lang)
}
class Elastic {
private client: Client
constructor() {
this.client = new Client({
node: "http://localhost:9200",
})
}
public updateMappings = async () => {
await this.client.indices.putMapping({
index: INDEX_NAME,
properties: {
bodyText: {
type: "text",
analyzer: "russian",
},
},
})
}
public createIndex = async (lang: Languages) => {
const indexName = getIndexNameByLang(lang)
const analyzer = getAnalyzerByLang(lang)
await this.client.indices.create({
index: indexName,
mappings: {
properties: {
bodyText: {
type: "text",
analyzer,
},
title: {
type: "text",
analyzer,
},
h1: {
type: "text",
analyzer,
},
description: {
type: "text",
analyzer,
},
},
},
})
}
public initElastic = async () => {
;[Languages.EN, Languages.RU].forEach(async (item) => {
await this.createIndex(item)
})
}
public index = async (params: ElasticIndexParams) => {
const indexName = getIndexNameByText(params.title + params.bodyText)
await this.client.index({
index: indexName,
id: params.url,
document: {
url: params.url,
title: params.title,
h1: params.h1,
bodyText: params.bodyText,
description: params.description,
},
})
}
public search = async ({ text, page = 0 }: ElasticSearchParams) => {
const indexName = getIndexNameByText(text)
const from = page * SEARCH_PER_PAGE
const result = await this.client.search({
index: indexName,
size: SEARCH_PER_PAGE,
from,
query: {
multi_match: {
query: text,
fields: ["title^4", "description^3", "h1^2", "bodyText"],
},
},
})
return {
hits: result.hits.hits,
// @ts-ignore
total: result.hits.total?.value,
}
}
}
export default new Elastic()