]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add tests for the example fts3 "rank" function that appears in the
authordan <dan@noemail.net>
Fri, 6 Oct 2017 18:00:36 +0000 (18:00 +0000)
committerdan <dan@noemail.net>
Fri, 6 Oct 2017 18:00:36 +0000 (18:00 +0000)
documentation.

FossilOrigin-Name: 702b137aa4f76543647e177beeb1ca2b3cd18c61021c78880e9aa8656f341d65

manifest
manifest.uuid
src/test_func.c
test/fts3rank.test [new file with mode: 0644]

index 78578c42d7de999b274f43028670f999c2b9a0df..9ed6440a7079d5f0fea348951cb93653c1c3cb30 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\scompiler\swarnings\sthat\scome\sup\swith\sSQLITE_OMIT_WAL.
-D 2017-10-05T20:57:38.304
+C Add\stests\sfor\sthe\sexample\sfts3\s"rank"\sfunction\sthat\sappears\sin\sthe\ndocumentation.
+D 2017-10-06T18:00:36.541
 F Makefile.in 4bc36d913c2e3e2d326d588d72f618ac9788b2fd4b7efda61102611a6495c3ff
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc 6033b51b6aea702ea059f6ab2d47b1d3cef648695f787247dd4fb395fe60673f
@@ -489,7 +489,7 @@ F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf
 F src/test_demovfs.c a0c3bdd45ed044115c2c9f7779e56eafff18741e
 F src/test_devsym.c 1960abbb234b97e9b920f07e99503fc04b443f62bbc3c6ff2c2cea2133e3b8a2
 F src/test_fs.c 35a2f7dd8a915900873386331386d9ba1ae1b5026d74fd20c2807bc76221f291
-F src/test_func.c a4fdab3363b436c1b12660e9362ce3f3782b7b5e
+F src/test_func.c 772bb74807d3485ce90c9347f5dfddec4a76ed9edd4cf6c58d2d79b9ce9064d6
 F src/test_hexio.c 1d4469ca61ab202a1fcec6543f584d2407205e8d
 F src/test_init.c 4413c211a94b62157ca4c145b3f27c497f03c664
 F src/test_intarray.c 988fc61cb0ff539f4172c0d95f15287c92516f64
@@ -864,6 +864,7 @@ F test/fts3offsets.test b85fd382abdc78ebce721d8117bd552dfb75094c
 F test/fts3prefix.test fa794eaab0bdae466494947b0b153d7844478ab2
 F test/fts3prefix2.test e1f0a822ca661dced7f12ce392e14eaf65609dce
 F test/fts3query.test f33eb71a1fe1084ea585eeb7ee76b390729f5170
+F test/fts3rank.test e4d2e16a28c98cae95001a75e2b4b05b19b051ffd6aaab15491c5e0595127b9b
 F test/fts3rnd.test 1320d8826a845e38a96e769562bf83d7a92a15d0
 F test/fts3shared.test 57e26a801f21027b7530da77db54286a6fe4997e
 F test/fts3snippet.test 01a4231816e03a0660ae53ba2404fe69012fe0db
@@ -1655,7 +1656,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 373b0ace480aa303bbf512ea8806a17f6186b16d6316a7b724499bf94b3974d4
-R adacc5e670ad3c34f8576daa184cae71
-U drh
-Z 9327d763f0b9382eb519713049c15b88
+P 8ca0fa8dfe6a66aea7fc63f15e6f704cb190aa0760a3fec2db5f6bad3861a135
+R 413648e1416f08d1828bb75a07c656dd
+U dan
+Z b857c7dffd71ebfaddd17b63d1fd16c3
index 9c51f15a9ce37f8acd9641f8bfe55fa1669cf6b4..b8a9eb4154a5699f71eeff87879651a3251f95f3 100644 (file)
@@ -1 +1 @@
-8ca0fa8dfe6a66aea7fc63f15e6f704cb190aa0760a3fec2db5f6bad3861a135
\ No newline at end of file
+702b137aa4f76543647e177beeb1ca2b3cd18c61021c78880e9aa8656f341d65
\ No newline at end of file
index c7860fe8877c4bdc3611a1df4c79968f5812ddbe..59fe677c3384dc664fe8492193ac143ae9f75f6c 100644 (file)
@@ -791,6 +791,123 @@ abuse_err:
 }
 
 
+/*
+** SQLite user defined function to use with matchinfo() to calculate the
+** relevancy of an FTS match. The value returned is the relevancy score
+** (a real value greater than or equal to zero). A larger value indicates 
+** a more relevant document.
+**
+** The overall relevancy returned is the sum of the relevancies of each 
+** column value in the FTS table. The relevancy of a column value is the
+** sum of the following for each reportable phrase in the FTS query:
+**
+**   (<hit count> / <global hit count>) * <column weight>
+**
+** where <hit count> is the number of instances of the phrase in the
+** column value of the current row and <global hit count> is the number
+** of instances of the phrase in the same column of all rows in the FTS
+** table. The <column weight> is a weighting factor assigned to each
+** column by the caller (see below).
+**
+** The first argument to this function must be the return value of the FTS 
+** matchinfo() function. Following this must be one argument for each column 
+** of the FTS table containing a numeric weight factor for the corresponding 
+** column. Example:
+**
+**     CREATE VIRTUAL TABLE documents USING fts3(title, content)
+**
+** The following query returns the docids of documents that match the full-text
+** query <query> sorted from most to least relevant. When calculating
+** relevance, query term instances in the 'title' column are given twice the
+** weighting of those in the 'content' column.
+**
+**     SELECT docid FROM documents 
+**     WHERE documents MATCH <query> 
+**     ORDER BY rank(matchinfo(documents), 1.0, 0.5) DESC
+*/
+static void rankfunc(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal){
+  int *aMatchinfo;                /* Return value of matchinfo() */
+  int nMatchinfo;                 /* Number of elements in aMatchinfo[] */
+  int nCol = 0;                   /* Number of columns in the table */
+  int nPhrase = 0;                /* Number of phrases in the query */
+  int iPhrase;                    /* Current phrase */
+  double score = 0.0;             /* Value to return */
+
+  assert( sizeof(int)==4 );
+
+  /* Check that the number of arguments passed to this function is correct.
+  ** If not, jump to wrong_number_args. Set aMatchinfo to point to the array
+  ** of unsigned integer values returned by FTS function matchinfo. Set
+  ** nPhrase to contain the number of reportable phrases in the users full-text
+  ** query, and nCol to the number of columns in the table. Then check that the
+  ** size of the matchinfo blob is as expected. Return an error if it is not.
+  */
+  if( nVal<1 ) goto wrong_number_args;
+  aMatchinfo = (unsigned int *)sqlite3_value_blob(apVal[0]);
+  nMatchinfo = sqlite3_value_bytes(apVal[0]) / sizeof(int);
+  if( nMatchinfo>=2 ){
+    nPhrase = aMatchinfo[0];
+    nCol = aMatchinfo[1];
+  }
+  if( nMatchinfo!=(2+3*nCol*nPhrase) ){
+    sqlite3_result_error(pCtx,
+        "invalid matchinfo blob passed to function rank()", -1);
+    return;
+  }
+  if( nVal!=(1+nCol) ) goto wrong_number_args;
+
+  /* Iterate through each phrase in the users query. */
+  for(iPhrase=0; iPhrase<nPhrase; iPhrase++){
+    int iCol;                     /* Current column */
+
+    /* Now iterate through each column in the users query. For each column,
+    ** increment the relevancy score by:
+    **
+    **   (<hit count> / <global hit count>) * <column weight>
+    **
+    ** aPhraseinfo[] points to the start of the data for phrase iPhrase. So
+    ** the hit count and global hit counts for each column are found in 
+    ** aPhraseinfo[iCol*3] and aPhraseinfo[iCol*3+1], respectively.
+    */
+    int *aPhraseinfo = &aMatchinfo[2 + iPhrase*nCol*3];
+    for(iCol=0; iCol<nCol; iCol++){
+      int nHitCount = aPhraseinfo[3*iCol];
+      int nGlobalHitCount = aPhraseinfo[3*iCol+1];
+      double weight = sqlite3_value_double(apVal[iCol+1]);
+      if( nHitCount>0 ){
+        score += ((double)nHitCount / (double)nGlobalHitCount) * weight;
+      }
+    }
+  }
+
+  sqlite3_result_double(pCtx, score);
+  return;
+
+  /* Jump here if the wrong number of arguments are passed to this function */
+wrong_number_args:
+  sqlite3_result_error(pCtx, "wrong number of arguments to function rank()", -1);
+}
+
+static int SQLITE_TCLAPI install_fts3_rank_function(
+  void * clientData,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+  extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
+  sqlite3 *db;
+
+  if( objc!=2 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "DB");
+    return TCL_ERROR;
+  }
+
+  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+  sqlite3_create_function(db, "rank", -1, SQLITE_UTF8, 0, rankfunc, 0, 0);
+  return TCL_OK;
+}
+
+
 /*
 ** Register commands with the TCL interpreter.
 */
@@ -801,6 +918,7 @@ int Sqlitetest_func_Init(Tcl_Interp *interp){
   } aObjCmd[] = {
      { "autoinstall_test_functions",    autoinstall_test_funcs },
      { "abuse_create_function",         abuse_create_function  },
+     { "install_fts3_rank_function",    install_fts3_rank_function  },
   };
   int i;
   extern int Md5_Register(sqlite3 *, char **, const sqlite3_api_routines *);
diff --git a/test/fts3rank.test b/test/fts3rank.test
new file mode 100644 (file)
index 0000000..7ee3143
--- /dev/null
@@ -0,0 +1,64 @@
+# 2017 October 7
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#*************************************************************************
+# This file implements regression tests for SQLite library.  The
+# focus of this script is testing the FTS3 module.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix fts3expr5
+
+# If SQLITE_ENABLE_FTS3 is defined, omit this file.
+ifcapable !fts3 {
+  finish_test
+  return
+}
+
+install_fts3_rank_function db
+do_execsql_test 1.0 {
+  CREATE VIRTUAL TABLE t1 USING fts3(a, b);
+  INSERT INTO t1 VALUES('one two', 'one');
+  INSERT INTO t1 VALUES('one two', 'three');
+  INSERT INTO t1 VALUES('one two', 'two');
+}
+
+do_execsql_test 1.1 {
+  SELECT * FROM t1 WHERE t1 MATCH 'one' 
+  ORDER BY rank(matchinfo(t1), 1.0, 1.0) DESC, rowid
+} {
+  {one two} one
+  {one two} three
+  {one two} two
+}
+
+do_execsql_test 1.2 {
+  SELECT * FROM t1 WHERE t1 MATCH 'two' 
+  ORDER BY rank(matchinfo(t1), 1.0, 1.0) DESC, rowid
+} {
+  {one two} two
+  {one two} one
+  {one two} three
+}
+
+do_catchsql_test 1.3 {
+  SELECT * FROM t1 ORDER BY rank(matchinfo(t1), 1.0, 1.0) DESC, rowid
+} {1 {invalid matchinfo blob passed to function rank()}}
+
+do_catchsql_test 1.4 {
+  SELECT * FROM t1 ORDER BY rank(x'0000000000000000') DESC, rowid
+} {0 {{one two} one {one two} three {one two} two}}
+
+do_catchsql_test 1.5 {
+  SELECT * FROM t1 ORDER BY rank(x'0100000001000000') DESC, rowid
+} {1 {invalid matchinfo blob passed to function rank()}}
+
+finish_test
+