test.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. //
  2. // $Id$
  3. //
  4. //
  5. // Copyright (c) 2001-2014, Andrew Aksyonoff
  6. // Copyright (c) 2008-2014, Sphinx Technologies Inc
  7. // All rights reserved
  8. //
  9. // This program is free software; you can redistribute it and/or modify
  10. // it under the terms of the GNU Library General Public License. You should
  11. // have received a copy of the LGPL license along with this program; if you
  12. // did not, you can find it at http://www.gnu.org/
  13. //
  14. #include <stdarg.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #if _WIN32
  18. #include <winsock2.h>
  19. #endif
  20. #include "sphinxclient.h"
  21. static sphinx_bool g_smoke = SPH_FALSE;
  22. static int g_failed = 0;
  23. void die ( const char * template, ... )
  24. {
  25. va_list ap;
  26. va_start ( ap, template );
  27. printf ( "FATAL: " );
  28. vprintf ( template, ap );
  29. printf ( "\n" );
  30. va_end ( ap );
  31. exit ( 1 );
  32. }
  33. void net_init ()
  34. {
  35. #if _WIN32
  36. // init WSA on Windows
  37. WSADATA wsa_data;
  38. int wsa_startup_err;
  39. wsa_startup_err = WSAStartup ( WINSOCK_VERSION, &wsa_data );
  40. if ( wsa_startup_err )
  41. die ( "failed to initialize WinSock2: error %d", wsa_startup_err );
  42. #endif
  43. }
  44. void test_query ( sphinx_client * client, const char * query, const char * index )
  45. {
  46. sphinx_result * res;
  47. int i, j, k, mva_len;
  48. unsigned int * mva;
  49. const char * field_names[2];
  50. int field_weights[2];
  51. field_names[0] = "title";
  52. field_names[1] = "content";
  53. field_weights[0] = 100;
  54. field_weights[1] = 1;
  55. sphinx_set_field_weights ( client, 2, field_names, field_weights );
  56. field_weights[0] = 1;
  57. field_weights[1] = 1;
  58. res = sphinx_query ( client, query, index, NULL );
  59. if ( !res )
  60. {
  61. g_failed += ( res==NULL );
  62. if ( !g_smoke )
  63. die ( "query failed: %s", sphinx_error(client) );
  64. }
  65. if ( g_smoke )
  66. printf ( "Query '%s' retrieved %d of %d matches.\n", query, res->total, res->total_found );
  67. else
  68. printf ( "Query '%s' retrieved %d of %d matches in %d.%03d sec.\n",
  69. query, res->total, res->total_found, res->time_msec/1000, res->time_msec%1000 );
  70. printf ( "Query stats:\n" );
  71. for ( i=0; i<res->num_words; i++ )
  72. printf ( "\t'%s' found %d times in %d documents\n",
  73. res->words[i].word, res->words[i].hits, res->words[i].docs );
  74. printf ( "\nMatches:\n" );
  75. for ( i=0; i<res->num_matches; i++ )
  76. {
  77. printf ( "%d. doc_id=%d, weight=%d", 1+i,
  78. (int)sphinx_get_id ( res, i ), sphinx_get_weight ( res, i ) );
  79. for ( j=0; j<res->num_attrs; j++ )
  80. {
  81. printf ( ", %s=", res->attr_names[j] );
  82. switch ( res->attr_types[j] )
  83. {
  84. case SPH_ATTR_MULTI64:
  85. case SPH_ATTR_MULTI:
  86. mva = sphinx_get_mva ( res, i, j );
  87. mva_len = *mva++;
  88. printf ( "(" );
  89. for ( k=0; k<mva_len; k++ )
  90. printf ( k ? ",%u" : "%u", ( res->attr_types[j]==SPH_ATTR_MULTI ? mva[k] : (unsigned int)sphinx_get_mva64_value ( mva, k ) ) );
  91. printf ( ")" );
  92. break;
  93. case SPH_ATTR_FLOAT: printf ( "%f", sphinx_get_float ( res, i, j ) ); break;
  94. case SPH_ATTR_STRING: printf ( "%s", sphinx_get_string ( res, i, j ) ); break;
  95. default: printf ( "%u", (unsigned int)sphinx_get_int ( res, i, j ) ); break;
  96. }
  97. }
  98. printf ( "\n" );
  99. }
  100. printf ( "\n" );
  101. }
  102. void test_excerpt ( sphinx_client * client )
  103. {
  104. const char * docs[] =
  105. {
  106. "this is my test text to be highlighted, and for the sake of the testing we need to pump its length somewhat",
  107. "another test text to be highlighted, below limit",
  108. "test number three, without phrase match",
  109. "final test, not only without phrase match, but also above limit and with swapped phrase text test as well"
  110. };
  111. const int ndocs = sizeof(docs)/sizeof(docs[0]);
  112. const char * words = "test text";
  113. const char * index = "test1";
  114. sphinx_excerpt_options opts;
  115. char ** res;
  116. int i, j;
  117. sphinx_init_excerpt_options ( &opts );
  118. opts.limit = 60;
  119. opts.around = 3;
  120. opts.allow_empty = SPH_FALSE;
  121. for ( j=0; j<2; j++ )
  122. {
  123. opts.exact_phrase = j;
  124. printf ( "exact_phrase=%d\n", j );
  125. res = sphinx_build_excerpts ( client, ndocs, docs, index, words, &opts );
  126. if ( !res )
  127. {
  128. g_failed += ( res==NULL );
  129. if ( !g_smoke )
  130. die ( "query failed: %s", sphinx_error(client) );
  131. }
  132. for ( i=0; i<ndocs; i++ )
  133. printf ( "n=%d, res=%s\n", 1+i, res[i] );
  134. printf ( "\n" );
  135. }
  136. }
  137. void test_excerpt_spz ( sphinx_client * client )
  138. {
  139. const char * docs[] =
  140. {
  141. "<efx_unidentified_table>"
  142. "The institutional investment manager it. Is Filing this report and."
  143. "<efx_test>"
  144. "It is signed hereby represent. That it is all information."
  145. "are It or is"
  146. "</efx_test>"
  147. "<efx_2>"
  148. "cool It is cooler"
  149. "</efx_2>"
  150. "It is another place!"
  151. "</efx_unidentified_table>"
  152. };
  153. const int ndocs = sizeof(docs)/sizeof(docs[0]);
  154. const char * words = "it is";
  155. const char * index = "test1";
  156. sphinx_excerpt_options opts;
  157. char ** res;
  158. int i, j;
  159. sphinx_init_excerpt_options ( &opts );
  160. opts.limit = 150;
  161. opts.limit_passages = 8;
  162. opts.around = 8;
  163. opts.html_strip_mode = "strip";
  164. opts.passage_boundary = "zone";
  165. opts.emit_zones = SPH_TRUE;
  166. for ( j=0; j<2; j++ )
  167. {
  168. if ( j==1 )
  169. {
  170. opts.passage_boundary = "sentence";
  171. opts.emit_zones = SPH_FALSE;
  172. }
  173. printf ( "passage_boundary=%s\n", opts.passage_boundary );
  174. res = sphinx_build_excerpts ( client, ndocs, docs, index, words, &opts );
  175. if ( !res )
  176. die ( "query failed: %s", sphinx_error(client) );
  177. for ( i=0; i<ndocs; i++ )
  178. printf ( "n=%d, res=%s\n", 1+i, res[i] );
  179. printf ( "\n" );
  180. }
  181. }
  182. void test_persist_work ( sphinx_client * client )
  183. {
  184. char * docs[] = { NULL };
  185. const char words[] = "that is";
  186. const char * index = "test1";
  187. const char filler[] = " no need to worry about ";
  188. sphinx_excerpt_options opts;
  189. char ** res;
  190. char * doc;
  191. int i ;
  192. // should be in sync with sphinxclient.c MAX_PACKET_LEN
  193. i = 8*1024*1024 + 50;
  194. docs[0] = malloc ( i );
  195. if ( !docs[0] )
  196. die ( "malloc failed at test_persist_work" );
  197. memcpy ( docs[0], words, sizeof(words)-1 );
  198. doc = docs[0] + sizeof(words)-1;
  199. while ( ( doc + sizeof(filler) )<docs[0]+i )
  200. {
  201. memcpy ( doc, filler, sizeof(filler)-1 );
  202. doc += sizeof(filler)-1;
  203. }
  204. *doc = '\0';
  205. sphinx_open ( client );
  206. for ( i=0; i<2; i++ )
  207. {
  208. if ( i==0 )
  209. {
  210. sphinx_init_excerpt_options ( &opts );
  211. opts.limit = 0;
  212. opts.limit_passages = 0;
  213. opts.around = 0;
  214. opts.html_strip_mode = "none";
  215. opts.query_mode = SPH_TRUE;
  216. } else
  217. {
  218. sphinx_init_excerpt_options ( &opts );
  219. opts.limit = 500;
  220. opts.limit_words = 10;
  221. opts.limit_passages = 2;
  222. opts.around = 5;
  223. opts.html_strip_mode = "none";
  224. opts.query_mode = SPH_TRUE;
  225. *( docs[0]+sizeof(words)+100 ) = '\0';
  226. }
  227. printf ( "n=%d,\t", i );
  228. res = sphinx_build_excerpts ( client, 1, docs, index, words, &opts );
  229. if ( !res )
  230. {
  231. g_failed += ( res==NULL && i ); // 1st query fails, 2nd works
  232. printf ( "query failed: %s", sphinx_error(client) );
  233. } else
  234. {
  235. printf ( "res=%s", res[0] );
  236. free ( res );
  237. }
  238. printf ( "\n" );
  239. }
  240. sphinx_close ( client );
  241. printf ( "\n" );
  242. }
  243. void test_update ( sphinx_client * client, sphinx_uint64_t id )
  244. {
  245. const char * attr = "group_id";
  246. const sphinx_int64_t val = 123;
  247. int res;
  248. res = sphinx_update_attributes ( client, "test1", 1, &attr, 1, &id, &val );
  249. if ( res<0 )
  250. g_failed++;
  251. if ( res<0 )
  252. printf ( "update failed: %s\n\n", sphinx_error(client) );
  253. else
  254. printf ( "update success, %d rows updated\n\n", res );
  255. }
  256. void test_update_mva ( sphinx_client * client )
  257. {
  258. const char * attr = "tag";
  259. const sphinx_uint64_t id = 3;
  260. const unsigned int vals[] = { 7, 77, 177 };
  261. int res;
  262. res = sphinx_update_attributes_mva ( client, "test1", attr, id, sizeof(vals)/sizeof(vals[0]), vals );
  263. if ( res<0 )
  264. g_failed++;
  265. if ( res<0 )
  266. printf ( "update mva failed: %s\n\n", sphinx_error(client) );
  267. else
  268. printf ( "update mva success, %d rows updated\n\n", res );
  269. }
  270. void test_keywords ( sphinx_client * client )
  271. {
  272. int i, nwords;
  273. sphinx_keyword_info * words;
  274. words = sphinx_build_keywords ( client, "hello test one", "test1", SPH_TRUE, &nwords );
  275. g_failed += ( words==NULL );
  276. if ( !words )
  277. {
  278. printf ( "build_keywords failed: %s\n\n", sphinx_error(client) );
  279. } else
  280. {
  281. printf ( "build_keywords result:\n" );
  282. for ( i=0; i<nwords; i++ )
  283. printf ( "%d. tokenized=%s, normalized=%s, docs=%d, hits=%d\n", 1+i,
  284. words[i].tokenized, words[i].normalized,
  285. words[i].num_docs, words[i].num_hits );
  286. printf ( "\n" );
  287. }
  288. }
  289. void test_status ( sphinx_client * client )
  290. {
  291. int num_rows, num_cols, i, j, k;
  292. char ** status;
  293. status = sphinx_status ( client, &num_rows, &num_cols );
  294. if ( !status )
  295. {
  296. g_failed++;
  297. printf ( "status failed: %s\n\n", sphinx_error(client) );
  298. return;
  299. }
  300. k = 0;
  301. for ( i=0; i<num_rows; i++ )
  302. {
  303. if ( !g_smoke || ( strstr ( status[k], "time" )==NULL && strstr ( status[k], "wall" )==NULL && strstr ( status[k], "wait" )==NULL ) )
  304. {
  305. for ( j=0; j<num_cols; j++, k++ )
  306. printf ( ( j==0 ) ? "%s:" : " %s", status[k] );
  307. printf ( "\n" );
  308. } else
  309. k += num_cols;
  310. }
  311. printf ( "\n" );
  312. sphinx_status_destroy ( status, num_rows, num_cols );
  313. }
  314. void test_group_by ( sphinx_client * client, const char * attr )
  315. {
  316. sphinx_set_groupby ( client, attr, SPH_GROUPBY_ATTR, "@group asc" );
  317. test_query ( client, "is", "test1" );
  318. sphinx_reset_groupby ( client );
  319. }
  320. void test_filter ( sphinx_client * client )
  321. {
  322. const char * attr_group = "group_id";
  323. const char * attr_mva = "tag";
  324. sphinx_int64_t filter_group = { 1 };
  325. sphinx_int64_t filter_mva = { 7 };
  326. int i;
  327. sphinx_bool mva;
  328. for ( i=0; i<2; i++ )
  329. {
  330. mva = ( i==1 );
  331. sphinx_add_filter ( client, mva ? attr_mva : attr_group, 1, mva ? &filter_mva : &filter_group, SPH_FALSE );
  332. test_query ( client, "is", "test1" );
  333. sphinx_reset_filters ( client );
  334. }
  335. }
  336. void title ( const char * name )
  337. {
  338. if ( g_smoke || !name )
  339. return;
  340. printf ( "-> % s <-\n\n", name );
  341. }
  342. int main ( int argc, char ** argv )
  343. {
  344. int i, port = 0;
  345. sphinx_client * client;
  346. sphinx_uint64_t override_docid = 2;
  347. unsigned int override_value = 2000;
  348. for ( i=1; i<argc; i++ )
  349. {
  350. if ( strcmp ( argv[i], "--smoke" )==0 )
  351. g_smoke = SPH_TRUE;
  352. else if ( strcmp ( argv[i], "--port" )==0 && i+1<argc )
  353. port = (int)strtoul ( argv[i+1], NULL, 10 );
  354. }
  355. net_init ();
  356. client = sphinx_create ( SPH_TRUE );
  357. if ( !client )
  358. die ( "failed to create client" );
  359. if ( port )
  360. sphinx_set_server ( client, "127.0.0.1", port );
  361. sphinx_set_match_mode ( client, SPH_MATCH_EXTENDED2 );
  362. sphinx_set_sort_mode ( client, SPH_SORT_RELEVANCE, NULL );
  363. // excerpt + keywords
  364. title ( "excerpt" );
  365. test_excerpt ( client );
  366. test_excerpt_spz ( client );
  367. title ( "keywords" );
  368. test_keywords ( client );
  369. // search phase 0
  370. title ( "search phase 0" );
  371. test_query ( client, "is", "test1" );
  372. test_query ( client, "is test", "test1" );
  373. test_query ( client, "test number", "test1" );
  374. test_query ( client, "is", "dist" );
  375. // group_by (attr; mva) + filter
  376. title ( "group_by (attr; mva) + filter" );
  377. title ( "group_by attr" );
  378. test_group_by ( client, "group_id" );
  379. // group_by mva
  380. title ( "group_by mva" );
  381. test_group_by ( client, "tag" );
  382. // filter
  383. title ( "filter" );
  384. test_filter ( client );
  385. // update (attr; mva) + sort (descending id)
  386. title ( "update (attr; mva) + sort (descending id)" );
  387. test_update ( client, 2 );
  388. test_update_mva ( client );
  389. sphinx_set_sort_mode ( client, SPH_SORT_EXTENDED, "idd desc" );
  390. test_query ( client, "is", "test1" );
  391. // persistence connection
  392. sphinx_open ( client );
  393. // update (attr) + sort (default)
  394. title ( "update (attr) + sort (default)" );
  395. test_update ( client, 4 );
  396. test_update ( client, 3 );
  397. sphinx_set_sort_mode ( client, SPH_SORT_RELEVANCE, NULL );
  398. test_query ( client, "is", "test1" );
  399. sphinx_cleanup ( client );
  400. // group_by (attr; mva) + filter + post update
  401. title ( "group_by (attr; mva) + filter + post update" );
  402. title ( "group_by attr" );
  403. test_group_by ( client, "group_id" );
  404. title ( "group_by mva" );
  405. test_group_by ( client, "tag" );
  406. title ( "filter" );
  407. test_filter ( client );
  408. // select
  409. title ( "select" );
  410. sphinx_set_select ( client, "*, group_id*1000+@id*10 AS q" );
  411. test_query ( client, "is", "test1" );
  412. // override
  413. title ( "override" );
  414. sphinx_add_override ( client, "group_id", &override_docid, 1, &override_value );
  415. test_query ( client, "is", "test1" );
  416. // group_by (override attr)
  417. title ( "group_by (override attr)" );
  418. test_group_by ( client, "group_id" );
  419. sphinx_close ( client );
  420. test_status ( client );
  421. // long queries
  422. title ( "long queries vs persist connection" );
  423. test_persist_work ( client );
  424. sphinx_destroy ( client );
  425. if ( g_smoke && g_failed )
  426. {
  427. printf ( "%d error(s)\n", g_failed );
  428. exit ( 1 );
  429. }
  430. return 0;
  431. }
  432. //
  433. // $Id$
  434. //