|
@@ -12,7 +12,7 @@ module.exports = {
|
|
|
* INIT
|
|
|
*/
|
|
|
async init() {
|
|
|
- // -> Create Index
|
|
|
+ // -> Create Search Index
|
|
|
const indexExists = await WIKI.models.knex.schema.hasTable('pagesVector')
|
|
|
if (!indexExists) {
|
|
|
await WIKI.models.knex.schema.createTable('pagesVector', table => {
|
|
@@ -21,11 +21,19 @@ module.exports = {
|
|
|
table.string('locale')
|
|
|
table.string('title')
|
|
|
table.string('description')
|
|
|
- table.specificType('titleTk', 'TSVECTOR')
|
|
|
- table.specificType('descriptionTk', 'TSVECTOR')
|
|
|
- table.specificType('contentTk', 'TSVECTOR')
|
|
|
+ table.specificType('tokens', 'TSVECTOR')
|
|
|
})
|
|
|
}
|
|
|
+ // -> Create Words Index
|
|
|
+ const wordsExists = await WIKI.models.knex.schema.hasTable('pagesWords')
|
|
|
+ if (!wordsExists) {
|
|
|
+ await WIKI.models.knex.raw(`
|
|
|
+ CREATE TABLE "pagesWords" AS SELECT word FROM ts_stat(
|
|
|
+ 'SELECT to_tsvector(''simple'', pages."title") || to_tsvector(''simple'', pages."description") || to_tsvector(''simple'', pages."content") FROM pages WHERE pages."isPublished" AND NOT pages."isPrivate"'
|
|
|
+ )`)
|
|
|
+ await WIKI.models.knex.raw('CREATE EXTENSION IF NOT EXISTS pg_trgm')
|
|
|
+ await WIKI.models.knex.raw(`CREATE INDEX "pageWords_idx" ON "pagesWords" USING GIN (word gin_trgm_ops)`)
|
|
|
+ }
|
|
|
},
|
|
|
/**
|
|
|
* QUERY
|
|
@@ -35,14 +43,20 @@ module.exports = {
|
|
|
*/
|
|
|
async query(q, opts) {
|
|
|
try {
|
|
|
+ let suggestions = []
|
|
|
const results = await WIKI.models.knex.raw(`
|
|
|
SELECT id, path, locale, title, description
|
|
|
FROM "pagesVector", to_tsquery(?) query
|
|
|
- WHERE (query @@ "titleTk") OR (query @@ "descriptionTk") OR (query @@ "contentTk")
|
|
|
+ WHERE query @@ "tokens"
|
|
|
+ ORDER BY ts_rank(tokens, query) DESC
|
|
|
`, [tsquery(q)])
|
|
|
+ if (results.rows.length < 5) {
|
|
|
+ const suggestResults = await WIKI.models.knex.raw(`SELECT word, word <-> ? AS rank FROM "pagesWords" WHERE similarity(word, ?) > 0.2 ORDER BY rank LIMIT 5;`, [q, q])
|
|
|
+ suggestions = suggestResults.rows.map(r => r.word)
|
|
|
+ }
|
|
|
return {
|
|
|
results: results.rows,
|
|
|
- suggestions: [],
|
|
|
+ suggestions,
|
|
|
totalHits: results.rows.length
|
|
|
}
|
|
|
} catch (err) {
|
|
@@ -58,8 +72,8 @@ module.exports = {
|
|
|
*/
|
|
|
async created(page) {
|
|
|
await WIKI.models.knex.raw(`
|
|
|
- INSERT INTO "pagesVector" (path, locale, title, description, "titleTk", "descriptionTk", "contentTk") VALUES (
|
|
|
- '?', '?', '?', '?', to_tsvector('?'), to_tsvector('?'), to_tsvector('?')
|
|
|
+ INSERT INTO "pagesVector" (path, locale, title, description, tokens) VALUES (
|
|
|
+ '?', '?', '?', '?', (setweight(to_tsvector('${this.config.dictLanguage}', '?'), 'A') || setweight(to_tsvector('${this.config.dictLanguage}', '?'), 'B') || setweight(to_tsvector('${this.config.dictLanguage}', '?'), 'C'))
|
|
|
)
|
|
|
`, [page.path, page.locale, page.title, page.description, page.title, page.description, page.content])
|
|
|
},
|
|
@@ -73,9 +87,9 @@ module.exports = {
|
|
|
UPDATE "pagesVector" SET
|
|
|
title = '?',
|
|
|
description = '?',
|
|
|
- "titleTk" = to_tsvector('?'),
|
|
|
- "descriptionTk" = to_tsvector('?'),
|
|
|
- "contentTk" = to_tsvector('?')
|
|
|
+ tokens = (setweight(to_tsvector('${this.config.dictLanguage}', '?'), 'A') ||
|
|
|
+ setweight(to_tsvector('${this.config.dictLanguage}', '?'), 'B') ||
|
|
|
+ setweight(to_tsvector('${this.config.dictLanguage}', '?'), 'C'))
|
|
|
WHERE path = '?' AND locale = '?' LIMIT 1
|
|
|
`, [page.title, page.description, page.title, page.description, page.content, page.path, page.locale])
|
|
|
},
|
|
@@ -110,8 +124,11 @@ module.exports = {
|
|
|
async rebuild() {
|
|
|
await WIKI.models.knex('pagesVector').truncate()
|
|
|
await WIKI.models.knex.raw(`
|
|
|
- INSERT INTO "pagesVector" (path, locale, title, description, "titleTk", "descriptionTk", "contentTk")
|
|
|
- SELECT path, "localeCode" AS locale, title, description, to_tsvector(title) AS "titleTk", to_tsvector(description) AS "descriptionTk", to_tsvector(content) AS "contentTk"
|
|
|
+ INSERT INTO "pagesVector" (path, locale, title, description, "tokens")
|
|
|
+ SELECT path, "localeCode" AS locale, title, description,
|
|
|
+ (setweight(to_tsvector('${this.config.dictLanguage}', title), 'A') ||
|
|
|
+ setweight(to_tsvector('${this.config.dictLanguage}', description), 'B') ||
|
|
|
+ setweight(to_tsvector('${this.config.dictLanguage}', content), 'C')) AS tokens
|
|
|
FROM "pages"
|
|
|
WHERE pages."isPublished" AND NOT pages."isPrivate"`)
|
|
|
}
|