[Groonga-commit] groonga/gcs [master] bq: support query expansion in keyword

Back to archive index

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����������������������������...
다운로드 



More information about the Groonga-commit mailing list
Back to archive index