indexer_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. package core
  2. import (
  3. "testing"
  4. "github.com/huichen/wukong/types"
  5. "github.com/huichen/wukong/utils"
  6. )
  7. func TestAddKeywords(t *testing.T) {
  8. var indexer Indexer
  9. indexer.Init(types.IndexerInitOptions{IndexType: types.LocationsIndex})
  10. indexer.AddDocumentToCache(&types.DocumentIndex{
  11. DocId: 1,
  12. Keywords: []types.KeywordIndex{{"token1", 0, []int{}}},
  13. }, false)
  14. indexer.AddDocumentToCache(&types.DocumentIndex{
  15. DocId: 2,
  16. Keywords: []types.KeywordIndex{{"token2", 0, []int{}}},
  17. }, false)
  18. indexer.AddDocumentToCache(&types.DocumentIndex{
  19. DocId: 3,
  20. Keywords: []types.KeywordIndex{{"token3", 0, []int{}}},
  21. }, false)
  22. indexer.AddDocumentToCache(&types.DocumentIndex{
  23. DocId: 7,
  24. Keywords: []types.KeywordIndex{{"token7", 0, []int{}}},
  25. }, false)
  26. indexer.AddDocumentToCache(&types.DocumentIndex{
  27. DocId: 1,
  28. Keywords: []types.KeywordIndex{{"token2", 0, []int{}}},
  29. }, false)
  30. indexer.AddDocumentToCache(&types.DocumentIndex{
  31. DocId: 7,
  32. Keywords: []types.KeywordIndex{{"token77", 0, []int{}}},
  33. }, false)
  34. indexer.AddDocumentToCache(nil, true)
  35. utils.Expect(t, "", indicesToString(&indexer, "token1"))
  36. utils.Expect(t, "1 2 ", indicesToString(&indexer, "token2"))
  37. utils.Expect(t, "3 ", indicesToString(&indexer, "token3"))
  38. utils.Expect(t, "7 ", indicesToString(&indexer, "token77"))
  39. }
  40. func TestRemoveDocument(t *testing.T) {
  41. var indexer Indexer
  42. indexer.Init(types.IndexerInitOptions{IndexType: types.LocationsIndex})
  43. // doc1 = "token2 token3"
  44. indexer.AddDocumentToCache(&types.DocumentIndex{
  45. DocId: 1,
  46. Keywords: []types.KeywordIndex{
  47. {"token2", 0, []int{0}},
  48. {"token3", 0, []int{7}},
  49. },
  50. }, false)
  51. // doc2 = "token1 token2 token3"
  52. indexer.AddDocumentToCache(&types.DocumentIndex{
  53. DocId: 2,
  54. Keywords: []types.KeywordIndex{
  55. {"token1", 0, []int{0}},
  56. {"token2", 0, []int{7}},
  57. },
  58. }, true)
  59. utils.Expect(t, "2 ", indicesToString(&indexer, "token1"))
  60. utils.Expect(t, "1 2 ", indicesToString(&indexer, "token2"))
  61. utils.Expect(t, "1 ", indicesToString(&indexer, "token3"))
  62. indexer.RemoveDocumentToCache(2, false)
  63. // doc1 = "token1 token3"
  64. indexer.AddDocumentToCache(&types.DocumentIndex{
  65. DocId: 1,
  66. Keywords: []types.KeywordIndex{
  67. {"token1", 0, []int{0}},
  68. {"token3", 0, []int{7}},
  69. },
  70. }, true)
  71. utils.Expect(t, "1 ", indicesToString(&indexer, "token1"))
  72. utils.Expect(t, "", indicesToString(&indexer, "token2"))
  73. utils.Expect(t, "1 ", indicesToString(&indexer, "token3"))
  74. // doc2 = "token1 token2 token3"
  75. indexer.AddDocumentToCache(&types.DocumentIndex{
  76. DocId: 2,
  77. Keywords: []types.KeywordIndex{
  78. {"token1", 0, []int{0}},
  79. {"token2", 0, []int{7}},
  80. {"token3", 0, []int{14}},
  81. },
  82. }, true)
  83. utils.Expect(t, "1 2 ", indicesToString(&indexer, "token1"))
  84. utils.Expect(t, "2 ", indicesToString(&indexer, "token2"))
  85. utils.Expect(t, "1 2 ", indicesToString(&indexer, "token3"))
  86. // doc3 = "token1 token3"
  87. indexer.AddDocumentToCache(&types.DocumentIndex{
  88. DocId: 3,
  89. Keywords: []types.KeywordIndex{
  90. {"token1", 0, []int{0}},
  91. {"token2", 0, []int{7}},
  92. },
  93. }, false)
  94. indexer.RemoveDocumentToCache(3, false)
  95. indexer.AddDocumentToCache(nil, true)
  96. utils.Expect(t, "1 2 ", indicesToString(&indexer, "token1"))
  97. utils.Expect(t, "2 ", indicesToString(&indexer, "token2"))
  98. utils.Expect(t, "1 2 ", indicesToString(&indexer, "token3"))
  99. }
  100. func TestLookupLocationsIndex(t *testing.T) {
  101. var indexer Indexer
  102. indexer.Init(types.IndexerInitOptions{IndexType: types.LocationsIndex})
  103. // doc1 = "token2 token3"
  104. indexer.AddDocumentToCache(&types.DocumentIndex{
  105. DocId: 1,
  106. Keywords: []types.KeywordIndex{
  107. {"token2", 0, []int{0}},
  108. {"token3", 0, []int{7}},
  109. },
  110. }, false)
  111. // doc2 = "token1 token2 token3"
  112. indexer.AddDocumentToCache(&types.DocumentIndex{
  113. DocId: 2,
  114. Keywords: []types.KeywordIndex{
  115. {"token1", 0, []int{0}},
  116. {"token2", 0, []int{7}},
  117. {"token3", 0, []int{14}},
  118. },
  119. }, false)
  120. // doc3 = "token1 token2"
  121. indexer.AddDocumentToCache(&types.DocumentIndex{
  122. DocId: 3,
  123. Keywords: []types.KeywordIndex{
  124. {"token1", 0, []int{0}},
  125. {"token2", 0, []int{7}},
  126. },
  127. }, false)
  128. // doc4 = "token2"
  129. indexer.AddDocumentToCache(&types.DocumentIndex{
  130. DocId: 4,
  131. Keywords: []types.KeywordIndex{
  132. {"token2", 0, []int{0}},
  133. },
  134. }, false)
  135. // doc7 = "token1 token3"
  136. indexer.AddDocumentToCache(&types.DocumentIndex{
  137. DocId: 7,
  138. Keywords: []types.KeywordIndex{
  139. {"token1", 0, []int{0}},
  140. {"token3", 0, []int{7}},
  141. },
  142. }, false)
  143. // doc9 = "token3"
  144. indexer.AddDocumentToCache(&types.DocumentIndex{
  145. DocId: 9,
  146. Keywords: []types.KeywordIndex{
  147. {"token3", 0, []int{0}},
  148. },
  149. }, true)
  150. utils.Expect(t, "2 3 7 ", indicesToString(&indexer, "token1"))
  151. utils.Expect(t, "1 2 3 4 ", indicesToString(&indexer, "token2"))
  152. utils.Expect(t, "1 2 7 9 ", indicesToString(&indexer, "token3"))
  153. utils.Expect(t, "", indexedDocsToString(indexer.Lookup([]string{"token4"}, []string{}, nil, false)))
  154. utils.Expect(t, "[7 0 [0]] [3 0 [0]] [2 0 [0]] ",
  155. indexedDocsToString(indexer.Lookup([]string{"token1"}, []string{}, nil, false)))
  156. utils.Expect(t, "", indexedDocsToString(indexer.Lookup([]string{"token1", "token4"}, []string{}, nil, false)))
  157. utils.Expect(t, "[3 1 [0 7]] [2 1 [0 7]] ",
  158. indexedDocsToString(indexer.Lookup([]string{"token1", "token2"}, []string{}, nil, false)))
  159. utils.Expect(t, "[3 13 [7 0]] [2 13 [7 0]] ",
  160. indexedDocsToString(indexer.Lookup([]string{"token2", "token1"}, []string{}, nil, false)))
  161. utils.Expect(t, "[7 1 [0 7]] [2 8 [0 14]] ",
  162. indexedDocsToString(indexer.Lookup([]string{"token1", "token3"}, []string{}, nil, false)))
  163. utils.Expect(t, "[7 13 [7 0]] [2 20 [14 0]] ",
  164. indexedDocsToString(indexer.Lookup([]string{"token3", "token1"}, []string{}, nil, false)))
  165. utils.Expect(t, "[2 1 [7 14]] [1 1 [0 7]] ",
  166. indexedDocsToString(indexer.Lookup([]string{"token2", "token3"}, []string{}, nil, false)))
  167. utils.Expect(t, "[2 13 [14 7]] [1 13 [7 0]] ",
  168. indexedDocsToString(indexer.Lookup([]string{"token3", "token2"}, []string{}, nil, false)))
  169. utils.Expect(t, "[2 2 [0 7 14]] ",
  170. indexedDocsToString(indexer.Lookup([]string{"token1", "token2", "token3"}, []string{}, nil, false)))
  171. utils.Expect(t, "[2 26 [14 7 0]] ",
  172. indexedDocsToString(indexer.Lookup([]string{"token3", "token2", "token1"}, []string{}, nil, false)))
  173. }
  174. func TestLookupDocIdsIndex(t *testing.T) {
  175. var indexer Indexer
  176. indexer.Init(types.IndexerInitOptions{IndexType: types.DocIdsIndex})
  177. // doc1 = "token2 token3"
  178. indexer.AddDocumentToCache(&types.DocumentIndex{
  179. DocId: 1,
  180. Keywords: []types.KeywordIndex{
  181. {"token2", 0, []int{0}},
  182. {"token3", 0, []int{7}},
  183. },
  184. }, false)
  185. // doc2 = "token1 token2 token3"
  186. indexer.AddDocumentToCache(&types.DocumentIndex{
  187. DocId: 2,
  188. Keywords: []types.KeywordIndex{
  189. {"token1", 0, []int{0}},
  190. {"token2", 0, []int{7}},
  191. {"token3", 0, []int{14}},
  192. },
  193. }, false)
  194. // doc3 = "token1 token2"
  195. indexer.AddDocumentToCache(&types.DocumentIndex{
  196. DocId: 3,
  197. Keywords: []types.KeywordIndex{
  198. {"token1", 0, []int{0}},
  199. {"token2", 0, []int{7}},
  200. },
  201. }, false)
  202. // doc4 = "token2"
  203. indexer.AddDocumentToCache(&types.DocumentIndex{
  204. DocId: 4,
  205. Keywords: []types.KeywordIndex{
  206. {"token2", 0, []int{0}},
  207. },
  208. }, false)
  209. // doc7 = "token1 token3"
  210. indexer.AddDocumentToCache(&types.DocumentIndex{
  211. DocId: 7,
  212. Keywords: []types.KeywordIndex{
  213. {"token1", 0, []int{0}},
  214. {"token3", 0, []int{7}},
  215. },
  216. }, false)
  217. // doc9 = "token3"
  218. indexer.AddDocumentToCache(&types.DocumentIndex{
  219. DocId: 9,
  220. Keywords: []types.KeywordIndex{
  221. {"token3", 0, []int{0}},
  222. },
  223. }, true)
  224. utils.Expect(t, "2 3 7 ", indicesToString(&indexer, "token1"))
  225. utils.Expect(t, "1 2 3 4 ", indicesToString(&indexer, "token2"))
  226. utils.Expect(t, "1 2 7 9 ", indicesToString(&indexer, "token3"))
  227. utils.Expect(t, "", indexedDocsToString(indexer.Lookup([]string{"token4"}, []string{}, nil, false)))
  228. utils.Expect(t, "[7 0 []] [3 0 []] [2 0 []] ",
  229. indexedDocsToString(indexer.Lookup([]string{"token1"}, []string{}, nil, false)))
  230. utils.Expect(t, "", indexedDocsToString(indexer.Lookup([]string{"token1", "token4"}, []string{}, nil, false)))
  231. utils.Expect(t, "[3 0 []] [2 0 []] ",
  232. indexedDocsToString(indexer.Lookup([]string{"token1", "token2"}, []string{}, nil, false)))
  233. utils.Expect(t, "[3 0 []] [2 0 []] ",
  234. indexedDocsToString(indexer.Lookup([]string{"token2", "token1"}, []string{}, nil, false)))
  235. utils.Expect(t, "[7 0 []] [2 0 []] ",
  236. indexedDocsToString(indexer.Lookup([]string{"token1", "token3"}, []string{}, nil, false)))
  237. utils.Expect(t, "[7 0 []] [2 0 []] ",
  238. indexedDocsToString(indexer.Lookup([]string{"token3", "token1"}, []string{}, nil, false)))
  239. utils.Expect(t, "[2 0 []] [1 0 []] ",
  240. indexedDocsToString(indexer.Lookup([]string{"token2", "token3"}, []string{}, nil, false)))
  241. utils.Expect(t, "[2 0 []] [1 0 []] ",
  242. indexedDocsToString(indexer.Lookup([]string{"token3", "token2"}, []string{}, nil, false)))
  243. utils.Expect(t, "[2 0 []] ",
  244. indexedDocsToString(indexer.Lookup([]string{"token1", "token2", "token3"}, []string{}, nil, false)))
  245. utils.Expect(t, "[2 0 []] ",
  246. indexedDocsToString(indexer.Lookup([]string{"token3", "token2", "token1"}, []string{}, nil, false)))
  247. }
  248. func TestLookupWithProximity(t *testing.T) {
  249. var indexer Indexer
  250. indexer.Init(types.IndexerInitOptions{IndexType: types.LocationsIndex})
  251. // doc1 = "token2 token4 token4 token2 token3 token4"
  252. indexer.AddDocumentToCache(&types.DocumentIndex{
  253. DocId: 1,
  254. Keywords: []types.KeywordIndex{
  255. {"token2", 0, []int{0, 21}},
  256. {"token3", 0, []int{28}},
  257. {"token4", 0, []int{7, 14, 35}},
  258. },
  259. }, true)
  260. utils.Expect(t, "[1 1 [21 28]] ",
  261. indexedDocsToString(indexer.Lookup([]string{"token2", "token3"}, []string{}, nil, false)))
  262. // doc1 = "t2 t1 . . . t2 t3"
  263. indexer.AddDocumentToCache(&types.DocumentIndex{
  264. DocId: 1,
  265. Keywords: []types.KeywordIndex{
  266. {"t1", 0, []int{3}},
  267. {"t2", 0, []int{0, 12}},
  268. {"t3", 0, []int{15}},
  269. },
  270. }, true)
  271. utils.Expect(t, "[1 8 [3 12 15]] ",
  272. indexedDocsToString(indexer.Lookup([]string{"t1", "t2", "t3"}, []string{}, nil, false)))
  273. // doc1 = "t3 t2 t1 . . . . . t2 t3"
  274. indexer.AddDocumentToCache(&types.DocumentIndex{
  275. DocId: 1,
  276. Keywords: []types.KeywordIndex{
  277. {"t1", 0, []int{6}},
  278. {"t2", 0, []int{3, 19}},
  279. {"t3", 0, []int{0, 22}},
  280. },
  281. }, true)
  282. utils.Expect(t, "[1 10 [6 3 0]] ",
  283. indexedDocsToString(indexer.Lookup([]string{"t1", "t2", "t3"}, []string{}, nil, false)))
  284. }
  285. func TestLookupWithPartialLocations(t *testing.T) {
  286. var indexer Indexer
  287. indexer.Init(types.IndexerInitOptions{IndexType: types.LocationsIndex})
  288. // doc1 = "token2 token4 token4 token2 token3 token4" + "label1"(不在文本中)
  289. indexer.AddDocumentToCache(&types.DocumentIndex{
  290. DocId: 1,
  291. Keywords: []types.KeywordIndex{
  292. {"token2", 0, []int{0, 21}},
  293. {"token3", 0, []int{28}},
  294. {"label1", 0, []int{}},
  295. {"token4", 0, []int{7, 14, 35}},
  296. },
  297. }, false)
  298. // doc2 = "token2 token4 token4 token2 token3 token4"
  299. indexer.AddDocumentToCache(&types.DocumentIndex{
  300. DocId: 2,
  301. Keywords: []types.KeywordIndex{
  302. {"token2", 0, []int{0, 21}},
  303. {"token3", 0, []int{28}},
  304. {"token4", 0, []int{7, 14, 35}},
  305. },
  306. }, true)
  307. utils.Expect(t, "1 ", indicesToString(&indexer, "label1"))
  308. utils.Expect(t, "[1 1 [21 28]] ",
  309. indexedDocsToString(indexer.Lookup([]string{"token2", "token3"}, []string{"label1"}, nil, false)))
  310. }
  311. func TestLookupWithBM25(t *testing.T) {
  312. var indexer Indexer
  313. indexer.Init(types.IndexerInitOptions{
  314. IndexType: types.FrequenciesIndex,
  315. BM25Parameters: &types.BM25Parameters{
  316. K1: 1,
  317. B: 1,
  318. },
  319. })
  320. // doc1 = "token2 token4 token4 token2 token3 token4"
  321. indexer.AddDocumentToCache(&types.DocumentIndex{
  322. DocId: 1,
  323. TokenLength: 6,
  324. Keywords: []types.KeywordIndex{
  325. {"token2", 3, []int{0, 21}},
  326. {"token3", 7, []int{28}},
  327. {"token4", 15, []int{7, 14, 35}},
  328. },
  329. }, false)
  330. // doc2 = "token6 token7"
  331. indexer.AddDocumentToCache(&types.DocumentIndex{
  332. DocId: 2,
  333. TokenLength: 2,
  334. Keywords: []types.KeywordIndex{
  335. {"token6", 3, []int{0}},
  336. {"token7", 15, []int{7}},
  337. },
  338. }, true)
  339. outputs, _ := indexer.Lookup([]string{"token2", "token3", "token4"}, []string{}, nil, false)
  340. // BM25 = log2(3) * (12/9 + 28/17 + 60/33) = 6.3433
  341. utils.Expect(t, "76055", int(outputs[0].BM25*10000))
  342. }
  343. func TestLookupWithinDocIds(t *testing.T) {
  344. var indexer Indexer
  345. indexer.Init(types.IndexerInitOptions{IndexType: types.LocationsIndex})
  346. // doc1 = "token2 token3"
  347. indexer.AddDocumentToCache(&types.DocumentIndex{
  348. DocId: 1,
  349. Keywords: []types.KeywordIndex{
  350. {"token2", 0, []int{0}},
  351. {"token3", 0, []int{7}},
  352. },
  353. }, false)
  354. // doc2 = "token1 token2 token3"
  355. indexer.AddDocumentToCache(&types.DocumentIndex{
  356. DocId: 2,
  357. Keywords: []types.KeywordIndex{
  358. {"token1", 0, []int{0}},
  359. {"token2", 0, []int{7}},
  360. {"token3", 0, []int{14}},
  361. },
  362. }, false)
  363. // doc3 = "token1 token2"
  364. indexer.AddDocumentToCache(&types.DocumentIndex{
  365. DocId: 3,
  366. Keywords: []types.KeywordIndex{
  367. {"token1", 0, []int{0}},
  368. {"token2", 0, []int{7}},
  369. },
  370. }, false)
  371. // doc4 = "token2"
  372. indexer.AddDocumentToCache(&types.DocumentIndex{
  373. DocId: 4,
  374. Keywords: []types.KeywordIndex{
  375. {"token2", 0, []int{0}},
  376. },
  377. }, true)
  378. docIds := make(map[uint64]bool)
  379. docIds[1] = true
  380. docIds[3] = true
  381. utils.Expect(t, "[3 0 [7]] [1 0 [0]] ",
  382. indexedDocsToString(indexer.Lookup([]string{"token2"}, []string{}, docIds, false)))
  383. }
  384. func TestLookupWithLocations(t *testing.T) {
  385. var indexer Indexer
  386. indexer.Init(types.IndexerInitOptions{IndexType: types.LocationsIndex})
  387. // doc1 = "token2 token4 token4 token2 token3 token4"
  388. indexer.AddDocumentToCache(&types.DocumentIndex{
  389. DocId: 1,
  390. Keywords: []types.KeywordIndex{
  391. {"token2", 0, []int{0, 21}},
  392. {"token3", 0, []int{28}},
  393. {"token4", 0, []int{7, 14, 35}},
  394. },
  395. }, true)
  396. // doc2 = "token2 token4 token4 token2 token3 token4"
  397. indexer.AddDocumentToCache(&types.DocumentIndex{
  398. DocId: 2,
  399. Keywords: []types.KeywordIndex{
  400. {"token3", 0, []int{0, 21}},
  401. {"token5", 0, []int{28}},
  402. {"token2", 0, []int{7, 14, 35}},
  403. },
  404. }, true)
  405. indexer.RemoveDocumentToCache(2, true)
  406. docs, _ := indexer.Lookup([]string{"token2", "token3"}, []string{}, nil, false)
  407. utils.Expect(t, "[[0 21] [28]]", docs[0].TokenLocations)
  408. }