|
|
@@ -437,42 +437,31 @@ SearchClient.prototype.initializeBoolQuery = function(query) {
|
|
|
return query;
|
|
|
};
|
|
|
|
|
|
-SearchClient.prototype.appendCriteriaForKeywordContains = function(query, keyword) {
|
|
|
+SearchClient.prototype.appendCriteriaForQueryString = function(query, queryString) {
|
|
|
query = this.initializeBoolQuery(query);
|
|
|
|
|
|
- const appendMultiMatchQuery = function(query, type, keywords) {
|
|
|
- let target;
|
|
|
- let operator = 'and';
|
|
|
- switch (type) {
|
|
|
- case 'not_match':
|
|
|
- target = query.body.query.bool.must_not;
|
|
|
- operator = 'or';
|
|
|
- break;
|
|
|
- case 'match':
|
|
|
- default:
|
|
|
- target = query.body.query.bool.must;
|
|
|
- }
|
|
|
+ // parse
|
|
|
+ let parsedKeywords = this.parseQueryString(queryString);
|
|
|
|
|
|
- target.push({
|
|
|
+ if (parsedKeywords.match.length > 0) {
|
|
|
+ const q = {
|
|
|
multi_match: {
|
|
|
- query: keywords.join(' '),
|
|
|
- // TODO: By user's i18n setting, change boost or search target fields
|
|
|
+ query: parsedKeywords.match.join(' '),
|
|
|
fields: ['path.ja^2', 'path.en^2', 'body.ja', 'body.en'],
|
|
|
- operator: operator,
|
|
|
},
|
|
|
- });
|
|
|
-
|
|
|
- return query;
|
|
|
- };
|
|
|
-
|
|
|
- let parsedKeywords = this.getParsedKeywords(keyword);
|
|
|
-
|
|
|
- if (parsedKeywords.match.length > 0) {
|
|
|
- query = appendMultiMatchQuery(query, 'match', parsedKeywords.match);
|
|
|
+ };
|
|
|
+ query.body.query.bool.must.push(q);
|
|
|
}
|
|
|
|
|
|
if (parsedKeywords.not_match.length > 0) {
|
|
|
- query = appendMultiMatchQuery(query, 'not_match', parsedKeywords.not_match);
|
|
|
+ const q = {
|
|
|
+ multi_match: {
|
|
|
+ query: parsedKeywords.not_match.join(' '),
|
|
|
+ fields: ['path.ja^2', 'path.en^2', 'body.ja', 'body.en'],
|
|
|
+ operator: 'or'
|
|
|
+ },
|
|
|
+ };
|
|
|
+ query.body.query.bool.must_not.push(q);
|
|
|
}
|
|
|
|
|
|
if (parsedKeywords.phrase.length > 0) {
|
|
|
@@ -512,19 +501,21 @@ SearchClient.prototype.appendCriteriaForKeywordContains = function(query, keywor
|
|
|
|
|
|
query.body.query.bool.must_not.push(notPhraseQueries);
|
|
|
}
|
|
|
-};
|
|
|
|
|
|
-SearchClient.prototype.appendCriteriaForPathFilter = function(query, path) {
|
|
|
- query = this.initializeBoolQuery(query);
|
|
|
+ if (parsedKeywords.prefix.length > 0) {
|
|
|
+ const queries = parsedKeywords.prefix.map(path => {
|
|
|
+ return { prefix: { 'path.raw': path } };
|
|
|
+ });
|
|
|
+ query.body.query.bool.filter.push({ bool: { should: queries } });
|
|
|
+ }
|
|
|
|
|
|
- if (path.match(/\/$/)) {
|
|
|
- path = path.substr(0, path.length - 1);
|
|
|
+ if (parsedKeywords.not_prefix.length > 0) {
|
|
|
+ const queries = parsedKeywords.not_prefix.map(path => {
|
|
|
+ return { prefix: { 'path.raw': path } };
|
|
|
+ });
|
|
|
+ query.body.query.bool.filter.push({ bool: { must_not: queries } });
|
|
|
}
|
|
|
- query.body.query.bool.filter.push({
|
|
|
- wildcard: {
|
|
|
- 'path.raw': path + '/*',
|
|
|
- },
|
|
|
- });
|
|
|
+
|
|
|
};
|
|
|
|
|
|
SearchClient.prototype.filterPagesByViewer = async function(query, user, userGroups) {
|
|
|
@@ -651,12 +642,12 @@ SearchClient.prototype.appendFunctionScore = function(query) {
|
|
|
};
|
|
|
};
|
|
|
|
|
|
-SearchClient.prototype.searchKeyword = async function(keyword, user, userGroups, option) {
|
|
|
+SearchClient.prototype.searchKeyword = async function(queryString, user, userGroups, option) {
|
|
|
const from = option.offset || null;
|
|
|
const size = option.limit || null;
|
|
|
const type = option.type || null;
|
|
|
const query = this.createSearchQuerySortedByScore();
|
|
|
- this.appendCriteriaForKeywordContains(query, keyword);
|
|
|
+ this.appendCriteriaForQueryString(query, queryString);
|
|
|
|
|
|
this.filterPagesByType(query, type);
|
|
|
await this.filterPagesByViewer(query, user, userGroups);
|
|
|
@@ -668,11 +659,7 @@ SearchClient.prototype.searchKeyword = async function(keyword, user, userGroups,
|
|
|
return this.search(query);
|
|
|
};
|
|
|
|
|
|
-SearchClient.prototype.searchByPath = async function(keyword, prefix) {
|
|
|
- // TODO path 名だけから検索
|
|
|
-};
|
|
|
-
|
|
|
-SearchClient.prototype.getParsedKeywords = function(keyword) {
|
|
|
+SearchClient.prototype.parseQueryString = function(queryString) {
|
|
|
let matchWords = [];
|
|
|
let notMatchWords = [];
|
|
|
let phraseWords = [];
|
|
|
@@ -680,15 +667,15 @@ SearchClient.prototype.getParsedKeywords = function(keyword) {
|
|
|
let prefixPaths = [];
|
|
|
let notPrefixPaths = [];
|
|
|
|
|
|
- keyword.trim();
|
|
|
- keyword = keyword.replace(/\s+/g, ' ');
|
|
|
+ queryString.trim();
|
|
|
+ queryString = queryString.replace(/\s+/g, ' ');
|
|
|
|
|
|
// First: Parse phrase keywords
|
|
|
let phraseRegExp = new RegExp(/(-?"[^"]+")/g);
|
|
|
- let phrases = keyword.match(phraseRegExp);
|
|
|
+ let phrases = queryString.match(phraseRegExp);
|
|
|
|
|
|
if (phrases !== null) {
|
|
|
- keyword = keyword.replace(phraseRegExp, '');
|
|
|
+ queryString = queryString.replace(phraseRegExp, '');
|
|
|
|
|
|
phrases.forEach(function(phrase) {
|
|
|
phrase.trim();
|
|
|
@@ -702,7 +689,7 @@ SearchClient.prototype.getParsedKeywords = function(keyword) {
|
|
|
}
|
|
|
|
|
|
// Second: Parse other keywords (include minus keywords)
|
|
|
- keyword.split(' ').forEach(function(word) {
|
|
|
+ queryString.split(' ').forEach(function(word) {
|
|
|
if (word === '') {
|
|
|
return;
|
|
|
}
|