mirror of https://github.com/Requarks/wiki.git
28 changed files with 365 additions and 80 deletions
Split View
Diff Options
-
1client/components/admin.vue
-
63client/components/admin/admin-search.vue
-
25client/components/common/nav-header.vue
-
4client/components/common/search-results.vue
-
1client/components/history.vue
-
1client/components/profile.vue
-
1client/components/source.vue
-
12client/graph/admin/search/search-mutation-rebuild-index.gql
-
4client/graph/admin/search/search-mutation-save-engines.gql
-
1client/graph/admin/search/search-query-engines.gql
-
2package.json
-
13server/graph/resolvers/search.js
-
2server/graph/schemas/page.graphql
-
5server/graph/schemas/search.graphql
-
4server/helpers/error.js
-
3server/models/pages.js
-
31server/models/searchEngines.js
-
1server/modules/search/algolia/definition.yml
-
1server/modules/search/aws/definition.yml
-
19server/modules/search/azure/definition.yml
-
217server/modules/search/azure/engine.js
-
1server/modules/search/db/definition.yml
-
1server/modules/search/elasticsearch/definition.yml
-
1server/modules/search/manticore/definition.yml
-
1server/modules/search/postgres/definition.yml
-
28server/modules/search/postgres/engine.js
-
1server/modules/search/solr/definition.yml
-
1server/modules/search/sphinx/definition.yml
@ -0,0 +1,12 @@ |
|||
mutation { |
|||
search { |
|||
rebuildIndex { |
|||
responseResult { |
|||
succeeded |
|||
errorCode |
|||
slug |
|||
message |
|||
} |
|||
} |
|||
} |
|||
} |
@ -1,26 +1,213 @@ |
|||
module.exports = { |
|||
activate() { |
|||
const _ = require('lodash') |
|||
const { SearchService, QueryType } = require('azure-search-client') |
|||
const request = require('request-promise') |
|||
const { pipeline } = require('stream') |
|||
|
|||
module.exports = { |
|||
async activate() { |
|||
// not used
|
|||
}, |
|||
deactivate() { |
|||
|
|||
async deactivate() { |
|||
// not used
|
|||
}, |
|||
query() { |
|||
/** |
|||
* INIT |
|||
*/ |
|||
async init() { |
|||
this.client = new SearchService(this.config.serviceName, this.config.adminKey) |
|||
|
|||
// -> Create Search Index
|
|||
const indexes = await this.client.indexes.list() |
|||
if (!_.find(_.get(indexes, 'result.value', []), ['name', this.config.indexName])) { |
|||
await this.client.indexes.create({ |
|||
name: this.config.indexName, |
|||
fields: [ |
|||
{ |
|||
name: 'id', |
|||
type: 'Edm.String', |
|||
key: true, |
|||
searchable: false |
|||
}, |
|||
{ |
|||
name: 'locale', |
|||
type: 'Edm.String', |
|||
searchable: false |
|||
}, |
|||
{ |
|||
name: 'path', |
|||
type: 'Edm.String', |
|||
searchable: false |
|||
}, |
|||
{ |
|||
name: 'title', |
|||
type: 'Edm.String', |
|||
searchable: true |
|||
}, |
|||
{ |
|||
name: 'description', |
|||
type: 'Edm.String', |
|||
searchable: true |
|||
}, |
|||
{ |
|||
name: 'content', |
|||
type: 'Edm.String', |
|||
searchable: true |
|||
} |
|||
], |
|||
scoringProfiles: [ |
|||
{ |
|||
name: 'fieldWeights', |
|||
text: { |
|||
weights: { |
|||
title: 4, |
|||
description: 3, |
|||
content: 1 |
|||
} |
|||
} |
|||
} |
|||
], |
|||
suggesters: [ |
|||
{ |
|||
name: 'suggestions', |
|||
searchMode: 'analyzingInfixMatching', |
|||
sourceFields: ['title', 'description', 'content'] |
|||
} |
|||
], |
|||
}) |
|||
} |
|||
}, |
|||
created() { |
|||
|
|||
/** |
|||
* QUERY |
|||
* |
|||
* @param {String} q Query |
|||
* @param {Object} opts Additional options |
|||
*/ |
|||
async query(q, opts) { |
|||
try { |
|||
let suggestions = [] |
|||
const results = await this.client.indexes.use(this.config.indexName).search({ |
|||
count: true, |
|||
scoringProfile: 'fieldWeights', |
|||
search: q, |
|||
select: 'id, locale, path, title, description', |
|||
queryType: QueryType.simple, |
|||
top: 50 |
|||
}) |
|||
if (results.result.value.length < 5) { |
|||
// Using plain request, not yet available in library...
|
|||
try { |
|||
const suggestResults = await request({ |
|||
uri: `https://${this.config.serviceName}.search.windows.net/indexes/${this.config.indexName}/docs/autocomplete`, |
|||
method: 'post', |
|||
qs: { |
|||
'api-version': '2017-11-11-Preview' |
|||
}, |
|||
headers: { |
|||
'api-key': this.config.adminKey, |
|||
'Content-Type': 'application/json' |
|||
}, |
|||
json: true, |
|||
body: { |
|||
autocompleteMode: 'oneTermWithContext', |
|||
search: q, |
|||
suggesterName: 'suggestions' |
|||
} |
|||
}) |
|||
suggestions = suggestResults.value.map(s => s.queryPlusText) |
|||
} catch (err) { |
|||
WIKI.logger.warn('Search Engine suggestion failure: ', err) |
|||
} |
|||
} |
|||
return { |
|||
results: results.result.value, |
|||
suggestions, |
|||
totalHits: results.result['@odata.count'] |
|||
} |
|||
} catch (err) { |
|||
WIKI.logger.warn('Search Engine Error:') |
|||
WIKI.logger.warn(err) |
|||
} |
|||
}, |
|||
updated() { |
|||
|
|||
/** |
|||
* CREATE |
|||
* |
|||
* @param {Object} page Page to create |
|||
*/ |
|||
async created(page) { |
|||
await this.client.indexes.use(this.config.indexName).index([ |
|||
{ |
|||
id: page.hash, |
|||
locale: page.localeCode, |
|||
path: page.path, |
|||
title: page.title, |
|||
description: page.description, |
|||
content: page.content |
|||
} |
|||
]) |
|||
}, |
|||
deleted() { |
|||
|
|||
/** |
|||
* UPDATE |
|||
* |
|||
* @param {Object} page Page to update |
|||
*/ |
|||
async updated(page) { |
|||
await this.client.indexes.use(this.config.indexName).index([ |
|||
{ |
|||
id: page.hash, |
|||
locale: page.localeCode, |
|||
path: page.path, |
|||
title: page.title, |
|||
description: page.description, |
|||
content: page.content |
|||
} |
|||
]) |
|||
}, |
|||
renamed() { |
|||
|
|||
/** |
|||
* DELETE |
|||
* |
|||
* @param {Object} page Page to delete |
|||
*/ |
|||
async deleted(page) { |
|||
await this.client.indexes.use(this.config.indexName).index([ |
|||
{ |
|||
'@search.action': 'delete', |
|||
id: page.hash |
|||
} |
|||
]) |
|||
}, |
|||
rebuild() { |
|||
|
|||
/** |
|||
* RENAME |
|||
* |
|||
* @param {Object} page Page to rename |
|||
*/ |
|||
async renamed(page) { |
|||
await this.client.indexes.use(this.config.indexName).index([ |
|||
{ |
|||
'@search.action': 'delete', |
|||
id: page.sourceHash |
|||
} |
|||
]) |
|||
await this.client.indexes.use(this.config.indexName).index([ |
|||
{ |
|||
id: page.destinationHash, |
|||
locale: page.localeCode, |
|||
path: page.destinationPath, |
|||
title: page.title, |
|||
description: page.description, |
|||
content: page.content |
|||
} |
|||
]) |
|||
}, |
|||
/** |
|||
* REBUILD INDEX |
|||
*/ |
|||
async rebuild() { |
|||
await pipeline( |
|||
WIKI.models.knex.column({ id: 'hash' }, 'path', { locale: 'localeCode' }, 'title', 'description', 'content').select().from('pages').where({ |
|||
isPublished: true, |
|||
isPrivate: false |
|||
}).stream(), |
|||
this.client.indexes.use(this.config.indexName).createIndexingStream() |
|||
) |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save