Kouhei Sutou
null+****@clear*****
Tue Aug 14 18:35:39 JST 2012
Kouhei Sutou 2012-08-14 18:35:39 +0900 (Tue, 14 Aug 2012) New Revision: 1b79691d49254a906174752a43b84760c5bf4429 https://github.com/groonga/gcs/commit/1b79691d49254a906174752a43b84760c5bf4429 Log: bq: support query expansion in keyword Modified files: lib/api/2011-02-01/search.js lib/bq-translator.js test/api-search.test.js test/bq-translator.test.js Modified: lib/api/2011-02-01/search.js (+2 -0) =================================================================== --- lib/api/2011-02-01/search.js 2012-08-14 18:11:09 +0900 (dc369c8) +++ lib/api/2011-02-01/search.js 2012-08-14 18:35:39 +0900 (4208432) @@ -106,6 +106,7 @@ exports.createHandler = function(context) { if (query) { var queryAsBooleanQuery = translateQueryToBooleanQuery(query); var translator = new BooleanQueryTranslator(queryAsBooleanQuery); + translator.domain = domain; translator.defaultFieldNames = defaultFieldNames; try { filters.push(translator.translate()); @@ -121,6 +122,7 @@ exports.createHandler = function(context) { if (booleanQuery) { var translator = new BooleanQueryTranslator(booleanQuery); + translator.domain = domain; translator.defaultFieldNames = defaultFieldNames; try { filters.push(translator.translate()); Modified: lib/bq-translator.js (+27 -11) =================================================================== --- lib/bq-translator.js 2012-08-14 18:11:09 +0900 (a394e71) +++ lib/bq-translator.js 2012-08-14 18:35:39 +0900 (fb0c9cf) @@ -17,6 +17,7 @@ function BooleanQueryTranslator(query) { this.query = query; this.offset = 0; + this.domain = null; this.defaultFieldNames = null; } @@ -217,27 +218,35 @@ BooleanQueryTranslator.prototype = { var tokens = []; var value = ""; + var self = this; + var addKeywordToken = function() { + if (value.length == 0) { + return; + } + var expandedKeywords = self.expandWord(value); + var keywordTokens = expandedKeywords.map(function(keyword) { + return this.translateExpressionValueStringKeyword(field, keyword); + }, self); + if (keywordTokens.length >= 2) { + tokens.push("(" + keywordTokens.join(" || ") + ")"); + } else { + tokens.push(keywordTokens[0]); + } + value = ""; + }; for (; this.offset < this.query.length; this.offset++) { var character = this.query[this.offset]; if (character == "'") { this.offset++; - if (value.length > 0) { - tokens.push(this.translateExpressionValueStringKeyword(field, value)); - } + addKeywordToken(); return tokens.join(" "); } if (character == " " || character == "+") { - if (value.length > 0) { - tokens.push(this.translateExpressionValueStringKeyword(field, value)); - value = ""; - } + addKeywordToken(); tokens.push("&&"); } else if (character == "|") { - if (value.length > 0) { - tokens.push(this.translateExpressionValueStringKeyword(field, value)); - value = ""; - } + addKeywordToken(); tokens.push("||"); } else if (character == "\\") { this.offset++; @@ -338,6 +347,13 @@ BooleanQueryTranslator.prototype = { return this.constructBinaryOperation(field, "==", min); } }, + expandWord: function(word) { + var synonym = this.domain.getSynonymSync(word); + if (!synonym) { + return [word]; + } + return synonym; + }, constructBinaryOperation: function(field, operator, value) { if (field) { return field + " " + operator + " " + value; Modified: test/api-search.test.js (+0 -1) =================================================================== --- test/api-search.test.js 2012-08-14 18:11:09 +0900 (73f87f9) +++ test/api-search.test.js 2012-08-14 18:35:39 +0900 (5204111) @@ -356,7 +356,6 @@ suite('Search API', function() { }); suite('with fixture and synonyms loaded', function() { - return; // TODO: Re-enable me. Disabled temporary setup(function() { utils.loadDumpFile(context, __dirname + '/fixture/companies/ddl.grn'); utils.loadDumpFile(context, __dirname + '/fixture/companies/data.grn'); Modified: test/bq-translator.test.js (+49 -14) =================================================================== --- test/bq-translator.test.js 2012-08-14 18:11:09 +0900 (e0662fc) +++ test/bq-translator.test.js 2012-08-14 18:35:39 +0900 (b72632a) @@ -5,11 +5,21 @@ var assert = require('chai').assert; var BooleanQueryTranslator = require('../lib/bq-translator').BooleanQueryTranslator; +function createTranslator(query) { + var translator = new BooleanQueryTranslator(query); + translator.domain = { + getSynonymSync: function(key) { + return null; + } + }; + translator.defaultFieldNames = ["field"]; + return translator; +} + function testQuery(label, query, expected) { test('query: ' + label + ': ' + '<' + query + '> -> <' + expected + '>', function() { - var translator = new BooleanQueryTranslator(query); - translator.defaultFieldNames = ["field"]; + var translator = createTranslator(query); assert.equal(translator.translate(), expected); }); @@ -17,8 +27,7 @@ function testQuery(label, query, expected) { function testQueryError(label, query, context, detail) { test('error: query: ' + label + ': ' + '<' + query + '>', function() { - var translator = new BooleanQueryTranslator(query); - translator.defaultFieldNames = ["field"]; + var translator = createTranslator(query); var actualError; assert.throw(function() { try { @@ -35,8 +44,7 @@ function testQueryError(label, query, context, detail) { function testGroup(label, group, expectedOffset, expectedScriptGrnExpr) { test('gorup: ' + label + ': ' + '<' + group + '> -> <' + expectedScriptGrnExpr + '>', function() { - var translator = new BooleanQueryTranslator(group); - translator.defaultFieldNames = ["field"]; + var translator = createTranslator(group); var actualScriptGrnExpr = translator.translateGroup(); assert.deepEqual({ scriptGrnExpr: actualScriptGrnExpr, @@ -51,8 +59,7 @@ function testGroup(label, group, expectedOffset, expectedScriptGrnExpr) { function testGroupError(label, group, context, detail) { test('error: group: ' + label + ': ' + '<' + group + '>', function() { - var translator = new BooleanQueryTranslator(group); - translator.defaultFieldNames = ["field"]; + var translator = createTranslator(group); var actualError; assert.throw(function() { try { @@ -70,8 +77,7 @@ function testExpression(label, expression, expectedOffset, expectedScriptGrnExpr) { test('expression: ' + label + ': ' + '<' + expression + '> -> <' + expectedScriptGrnExpr + '>', function() { - var translator = new BooleanQueryTranslator(expression); - translator.defaultFieldNames = ["field"]; + var translator = createTranslator(expression); var actualScriptGrnExpr = translator.translateExpression(); assert.deepEqual({ @@ -88,8 +94,7 @@ function testExpression(label, expression, function testExpressionError(label, expression, context, detail) { test('error: expression: ' + label + ': ' + '<' + expression + '>', function() { - var translator = new BooleanQueryTranslator(expression); - translator.defaultFieldNames = ["field"]; + var translator = createTranslator(expression); var actualError; assert.throw(function() { try { @@ -106,7 +111,7 @@ function testExpressionError(label, expression, context, detail) { function testDefaultFieldNames(label, query, defaultFieldNames, expected) { test('default field names: ' + label + ': ' + '<' + query + '> -> <' + expected + '>', function() { - var translator = new BooleanQueryTranslator(query); + var translator = createTranslator(query); translator.defaultFieldNames = defaultFieldNames; assert.equal(translator.translate(), expected); @@ -117,7 +122,7 @@ function testDefaultFieldNamesError(label, query, defaultFieldNames, context, detail) { test('error: default field names: ' + label + ': ' + '<' + query + '>', function() { - var translator = new BooleanQueryTranslator(query); + var translator = createTranslator(query); translator.defaultFieldNames = defaultFieldNames; var actualError; assert.throw(function() { @@ -132,6 +137,19 @@ function testDefaultFieldNamesError(label, query, defaultFieldNames, }); } +function testSynonym(label, query, synonyms, expected) { + test('default synonym: ' + label + ': ' + + '<' + query + '> -> <' + expected + '>', function() { + var translator = createTranslator(query); + translator.domain = { + getSynonymSync: function(key) { + return synonyms[key]; + } + }; + assert.equal(translator.translate(), expected); + }); +} + suite('BoolanQueryTranslator', function() { testQuery("expression", "type:'ModelName'", @@ -331,4 +349,21 @@ suite('BoolanQueryTranslator', function() { [], "'ModelName'||", "no default field"); + + testSynonym("existent: 0 synonym", + "'tokio'", + { tokio: [] }, + ''); + testSynonym("existent: 1 synonym", + "'tokio'", + { tokio: ["tokyo"] }, + 'field @ "tokyo"'); + testSynonym("existent: N synonyms", + "'tokio'", + { tokio: ["tokio", "tokyo"] }, + '(field @ "tokio" || field @ "tokyo")'); + testSynonym("nonexistent", + "'hokkaido'", + { tokio: ["tokio", "tokyo"] }, + 'field @ "hokkaido"'); }); -------------- next part -------------- HTML����������������������������...ダウンロード