indexer_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  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. }, true)
  94. indexer.RemoveDocumentToCache("3", true)
  95. utils.Expect(t, "1 2 ", indicesToString(&indexer, "token1"))
  96. utils.Expect(t, "2 ", indicesToString(&indexer, "token2"))
  97. utils.Expect(t, "1 2 ", indicesToString(&indexer, "token3"))
  98. // doc2 = "token1 token2 token3"
  99. indexer.AddDocumentToCache(&types.DocumentIndex{
  100. DocId: "2",
  101. Keywords: []types.KeywordIndex{
  102. {"token2", 0, []int{0}},
  103. {"token3", 0, []int{7}},
  104. },
  105. }, true)
  106. // doc3 = "token1 token3"
  107. indexer.AddDocumentToCache(&types.DocumentIndex{
  108. DocId: "3",
  109. Keywords: []types.KeywordIndex{
  110. {"token1", 0, []int{0}},
  111. {"token2", 0, []int{7}},
  112. },
  113. }, true)
  114. utils.Expect(t, "1 3 ", indicesToString(&indexer, "token1"))
  115. utils.Expect(t, "2 3 ", indicesToString(&indexer, "token2"))
  116. utils.Expect(t, "1 2 ", indicesToString(&indexer, "token3"))
  117. }
  118. func TestLookupLocationsIndex(t *testing.T) {
  119. var indexer Indexer
  120. indexer.Init(types.IndexerInitOptions{IndexType: types.LocationsIndex})
  121. // doc1 = "token2 token3"
  122. indexer.AddDocumentToCache(&types.DocumentIndex{
  123. DocId: "1",
  124. Keywords: []types.KeywordIndex{
  125. {"token2", 0, []int{0}},
  126. {"token3", 0, []int{7}},
  127. },
  128. }, false)
  129. // doc2 = "token1 token2 token3"
  130. indexer.AddDocumentToCache(&types.DocumentIndex{
  131. DocId: "2",
  132. Keywords: []types.KeywordIndex{
  133. {"token1", 0, []int{0}},
  134. {"token2", 0, []int{7}},
  135. {"token3", 0, []int{14}},
  136. },
  137. }, false)
  138. // doc3 = "token1 token2"
  139. indexer.AddDocumentToCache(&types.DocumentIndex{
  140. DocId: "3",
  141. Keywords: []types.KeywordIndex{
  142. {"token1", 0, []int{0}},
  143. {"token2", 0, []int{7}},
  144. },
  145. }, false)
  146. // doc4 = "token2"
  147. indexer.AddDocumentToCache(&types.DocumentIndex{
  148. DocId: "4",
  149. Keywords: []types.KeywordIndex{
  150. {"token2", 0, []int{0}},
  151. },
  152. }, false)
  153. // doc7 = "token1 token3"
  154. indexer.AddDocumentToCache(&types.DocumentIndex{
  155. DocId: "7",
  156. Keywords: []types.KeywordIndex{
  157. {"token1", 0, []int{0}},
  158. {"token3", 0, []int{7}},
  159. },
  160. }, false)
  161. // doc9 = "token3"
  162. indexer.AddDocumentToCache(&types.DocumentIndex{
  163. DocId: "9",
  164. Keywords: []types.KeywordIndex{
  165. {"token3", 0, []int{0}},
  166. },
  167. }, true)
  168. utils.Expect(t, "2 3 7 ", indicesToString(&indexer, "token1"))
  169. utils.Expect(t, "1 2 3 4 ", indicesToString(&indexer, "token2"))
  170. utils.Expect(t, "1 2 7 9 ", indicesToString(&indexer, "token3"))
  171. utils.Expect(t, "", indexedDocsToString(indexer.Lookup([]string{"token4"}, []string{}, nil, false)))
  172. utils.Expect(t, "[7 0 [0]] [3 0 [0]] [2 0 [0]] ",
  173. indexedDocsToString(indexer.Lookup([]string{"token1"}, []string{}, nil, false)))
  174. utils.Expect(t, "", indexedDocsToString(indexer.Lookup([]string{"token1", "token4"}, []string{}, nil, false)))
  175. utils.Expect(t, "[3 1 [0 7]] [2 1 [0 7]] ",
  176. indexedDocsToString(indexer.Lookup([]string{"token1", "token2"}, []string{}, nil, false)))
  177. utils.Expect(t, "[3 13 [7 0]] [2 13 [7 0]] ",
  178. indexedDocsToString(indexer.Lookup([]string{"token2", "token1"}, []string{}, nil, false)))
  179. utils.Expect(t, "[7 1 [0 7]] [2 8 [0 14]] ",
  180. indexedDocsToString(indexer.Lookup([]string{"token1", "token3"}, []string{}, nil, false)))
  181. utils.Expect(t, "[7 13 [7 0]] [2 20 [14 0]] ",
  182. indexedDocsToString(indexer.Lookup([]string{"token3", "token1"}, []string{}, nil, false)))
  183. utils.Expect(t, "[2 1 [7 14]] [1 1 [0 7]] ",
  184. indexedDocsToString(indexer.Lookup([]string{"token2", "token3"}, []string{}, nil, false)))
  185. utils.Expect(t, "[2 13 [14 7]] [1 13 [7 0]] ",
  186. indexedDocsToString(indexer.Lookup([]string{"token3", "token2"}, []string{}, nil, false)))
  187. utils.Expect(t, "[2 2 [0 7 14]] ",
  188. indexedDocsToString(indexer.Lookup([]string{"token1", "token2", "token3"}, []string{}, nil, false)))
  189. utils.Expect(t, "[2 26 [14 7 0]] ",
  190. indexedDocsToString(indexer.Lookup([]string{"token3", "token2", "token1"}, []string{}, nil, false)))
  191. }
  192. func TestLookupDocIdsIndex(t *testing.T) {
  193. var indexer Indexer
  194. indexer.Init(types.IndexerInitOptions{IndexType: types.DocIdsIndex})
  195. // doc1 = "token2 token3"
  196. indexer.AddDocumentToCache(&types.DocumentIndex{
  197. DocId: "1",
  198. Keywords: []types.KeywordIndex{
  199. {"token2", 0, []int{0}},
  200. {"token3", 0, []int{7}},
  201. },
  202. }, false)
  203. // doc2 = "token1 token2 token3"
  204. indexer.AddDocumentToCache(&types.DocumentIndex{
  205. DocId: "2",
  206. Keywords: []types.KeywordIndex{
  207. {"token1", 0, []int{0}},
  208. {"token2", 0, []int{7}},
  209. {"token3", 0, []int{14}},
  210. },
  211. }, false)
  212. // doc3 = "token1 token2"
  213. indexer.AddDocumentToCache(&types.DocumentIndex{
  214. DocId: "3",
  215. Keywords: []types.KeywordIndex{
  216. {"token1", 0, []int{0}},
  217. {"token2", 0, []int{7}},
  218. },
  219. }, false)
  220. // doc4 = "token2"
  221. indexer.AddDocumentToCache(&types.DocumentIndex{
  222. DocId: "4",
  223. Keywords: []types.KeywordIndex{
  224. {"token2", 0, []int{0}},
  225. },
  226. }, false)
  227. // doc7 = "token1 token3"
  228. indexer.AddDocumentToCache(&types.DocumentIndex{
  229. DocId: "7",
  230. Keywords: []types.KeywordIndex{
  231. {"token1", 0, []int{0}},
  232. {"token3", 0, []int{7}},
  233. },
  234. }, false)
  235. // doc9 = "token3"
  236. indexer.AddDocumentToCache(&types.DocumentIndex{
  237. DocId: "9",
  238. Keywords: []types.KeywordIndex{
  239. {"token3", 0, []int{0}},
  240. },
  241. }, true)
  242. utils.Expect(t, "2 3 7 ", indicesToString(&indexer, "token1"))
  243. utils.Expect(t, "1 2 3 4 ", indicesToString(&indexer, "token2"))
  244. utils.Expect(t, "1 2 7 9 ", indicesToString(&indexer, "token3"))
  245. utils.Expect(t, "", indexedDocsToString(indexer.Lookup([]string{"token4"}, []string{}, nil, false)))
  246. utils.Expect(t, "[7 0 []] [3 0 []] [2 0 []] ",
  247. indexedDocsToString(indexer.Lookup([]string{"token1"}, []string{}, nil, false)))
  248. utils.Expect(t, "", indexedDocsToString(indexer.Lookup([]string{"token1", "token4"}, []string{}, nil, false)))
  249. utils.Expect(t, "[3 0 []] [2 0 []] ",
  250. indexedDocsToString(indexer.Lookup([]string{"token1", "token2"}, []string{}, nil, false)))
  251. utils.Expect(t, "[3 0 []] [2 0 []] ",
  252. indexedDocsToString(indexer.Lookup([]string{"token2", "token1"}, []string{}, nil, false)))
  253. utils.Expect(t, "[7 0 []] [2 0 []] ",
  254. indexedDocsToString(indexer.Lookup([]string{"token1", "token3"}, []string{}, nil, false)))
  255. utils.Expect(t, "[7 0 []] [2 0 []] ",
  256. indexedDocsToString(indexer.Lookup([]string{"token3", "token1"}, []string{}, nil, false)))
  257. utils.Expect(t, "[2 0 []] [1 0 []] ",
  258. indexedDocsToString(indexer.Lookup([]string{"token2", "token3"}, []string{}, nil, false)))
  259. utils.Expect(t, "[2 0 []] [1 0 []] ",
  260. indexedDocsToString(indexer.Lookup([]string{"token3", "token2"}, []string{}, nil, false)))
  261. utils.Expect(t, "[2 0 []] ",
  262. indexedDocsToString(indexer.Lookup([]string{"token1", "token2", "token3"}, []string{}, nil, false)))
  263. utils.Expect(t, "[2 0 []] ",
  264. indexedDocsToString(indexer.Lookup([]string{"token3", "token2", "token1"}, []string{}, nil, false)))
  265. }
  266. func TestLookupWithProximity(t *testing.T) {
  267. var indexer Indexer
  268. indexer.Init(types.IndexerInitOptions{IndexType: types.LocationsIndex})
  269. // doc1 = "token2 token4 token4 token2 token3 token4"
  270. indexer.AddDocumentToCache(&types.DocumentIndex{
  271. DocId: "1",
  272. Keywords: []types.KeywordIndex{
  273. {"token2", 0, []int{0, 21}},
  274. {"token3", 0, []int{28}},
  275. {"token4", 0, []int{7, 14, 35}},
  276. },
  277. }, true)
  278. utils.Expect(t, "[1 1 [21 28]] ",
  279. indexedDocsToString(indexer.Lookup([]string{"token2", "token3"}, []string{}, nil, false)))
  280. // doc1 = "t2 t1 . . . t2 t3"
  281. indexer.AddDocumentToCache(&types.DocumentIndex{
  282. DocId: "1",
  283. Keywords: []types.KeywordIndex{
  284. {"t1", 0, []int{3}},
  285. {"t2", 0, []int{0, 12}},
  286. {"t3", 0, []int{15}},
  287. },
  288. }, true)
  289. utils.Expect(t, "[1 8 [3 12 15]] ",
  290. indexedDocsToString(indexer.Lookup([]string{"t1", "t2", "t3"}, []string{}, nil, false)))
  291. // doc1 = "t3 t2 t1 . . . . . t2 t3"
  292. indexer.AddDocumentToCache(&types.DocumentIndex{
  293. DocId: "1",
  294. Keywords: []types.KeywordIndex{
  295. {"t1", 0, []int{6}},
  296. {"t2", 0, []int{3, 19}},
  297. {"t3", 0, []int{0, 22}},
  298. },
  299. }, true)
  300. utils.Expect(t, "[1 10 [6 3 0]] ",
  301. indexedDocsToString(indexer.Lookup([]string{"t1", "t2", "t3"}, []string{}, nil, false)))
  302. }
  303. func TestLookupWithPartialLocations(t *testing.T) {
  304. var indexer Indexer
  305. indexer.Init(types.IndexerInitOptions{IndexType: types.LocationsIndex})
  306. // doc1 = "token2 token4 token4 token2 token3 token4" + "label1"(不在文本中)
  307. indexer.AddDocumentToCache(&types.DocumentIndex{
  308. DocId: "1",
  309. Keywords: []types.KeywordIndex{
  310. {"token2", 0, []int{0, 21}},
  311. {"token3", 0, []int{28}},
  312. {"label1", 0, []int{}},
  313. {"token4", 0, []int{7, 14, 35}},
  314. },
  315. }, false)
  316. // doc2 = "token2 token4 token4 token2 token3 token4"
  317. indexer.AddDocumentToCache(&types.DocumentIndex{
  318. DocId: "2",
  319. Keywords: []types.KeywordIndex{
  320. {"token2", 0, []int{0, 21}},
  321. {"token3", 0, []int{28}},
  322. {"token4", 0, []int{7, 14, 35}},
  323. },
  324. }, true)
  325. utils.Expect(t, "1 ", indicesToString(&indexer, "label1"))
  326. utils.Expect(t, "[1 1 [21 28]] ",
  327. indexedDocsToString(indexer.Lookup([]string{"token2", "token3"}, []string{"label1"}, nil, false)))
  328. }
  329. func TestLookupWithBM25(t *testing.T) {
  330. var indexer Indexer
  331. indexer.Init(types.IndexerInitOptions{
  332. IndexType: types.FrequenciesIndex,
  333. BM25Parameters: &types.BM25Parameters{
  334. K1: 1,
  335. B: 1,
  336. },
  337. })
  338. // doc1 = "token2 token4 token4 token2 token3 token4"
  339. indexer.AddDocumentToCache(&types.DocumentIndex{
  340. DocId: "1",
  341. TokenLength: 6,
  342. Keywords: []types.KeywordIndex{
  343. {"token2", 3, []int{0, 21}},
  344. {"token3", 7, []int{28}},
  345. {"token4", 15, []int{7, 14, 35}},
  346. },
  347. }, false)
  348. // doc2 = "token6 token7"
  349. indexer.AddDocumentToCache(&types.DocumentIndex{
  350. DocId: "2",
  351. TokenLength: 2,
  352. Keywords: []types.KeywordIndex{
  353. {"token6", 3, []int{0}},
  354. {"token7", 15, []int{7}},
  355. },
  356. }, true)
  357. outputs, _ := indexer.Lookup([]string{"token2", "token3", "token4"}, []string{}, nil, false)
  358. // BM25 = log2(3) * (12/9 + 28/17 + 60/33) = 6.3433
  359. utils.Expect(t, "76055", int(outputs[0].BM25*10000))
  360. }
  361. func TestLookupWithinDocIds(t *testing.T) {
  362. var indexer Indexer
  363. indexer.Init(types.IndexerInitOptions{IndexType: types.LocationsIndex})
  364. // doc1 = "token2 token3"
  365. indexer.AddDocumentToCache(&types.DocumentIndex{
  366. DocId: "1",
  367. Keywords: []types.KeywordIndex{
  368. {"token2", 0, []int{0}},
  369. {"token3", 0, []int{7}},
  370. },
  371. }, false)
  372. // doc2 = "token1 token2 token3"
  373. indexer.AddDocumentToCache(&types.DocumentIndex{
  374. DocId: "2",
  375. Keywords: []types.KeywordIndex{
  376. {"token1", 0, []int{0}},
  377. {"token2", 0, []int{7}},
  378. {"token3", 0, []int{14}},
  379. },
  380. }, false)
  381. // doc3 = "token1 token2"
  382. indexer.AddDocumentToCache(&types.DocumentIndex{
  383. DocId: "3",
  384. Keywords: []types.KeywordIndex{
  385. {"token1", 0, []int{0}},
  386. {"token2", 0, []int{7}},
  387. },
  388. }, false)
  389. // doc4 = "token2"
  390. indexer.AddDocumentToCache(&types.DocumentIndex{
  391. DocId: "4",
  392. Keywords: []types.KeywordIndex{
  393. {"token2", 0, []int{0}},
  394. },
  395. }, true)
  396. docIds := make(map[string]bool)
  397. docIds["1"] = true
  398. docIds["3"] = true
  399. utils.Expect(t, "[3 0 [7]] [1 0 [0]] ",
  400. indexedDocsToString(indexer.Lookup([]string{"token2"}, []string{}, docIds, false)))
  401. }
  402. func TestLookupWithLocations(t *testing.T) {
  403. var indexer Indexer
  404. indexer.Init(types.IndexerInitOptions{IndexType: types.LocationsIndex})
  405. // doc1 = "token2 token4 token4 token2 token3 token4"
  406. indexer.AddDocumentToCache(&types.DocumentIndex{
  407. DocId: "1",
  408. Keywords: []types.KeywordIndex{
  409. {"token2", 0, []int{0, 21}},
  410. {"token3", 0, []int{28}},
  411. {"token4", 0, []int{7, 14, 35}},
  412. },
  413. }, true)
  414. // doc2 = "token2 token4 token4 token2 token3 token4"
  415. indexer.AddDocumentToCache(&types.DocumentIndex{
  416. DocId: "2",
  417. Keywords: []types.KeywordIndex{
  418. {"token3", 0, []int{0, 21}},
  419. {"token5", 0, []int{28}},
  420. {"token2", 0, []int{7, 14, 35}},
  421. },
  422. }, true)
  423. indexer.RemoveDocumentToCache("2", true)
  424. docs, _ := indexer.Lookup([]string{"token2", "token3"}, []string{}, nil, false)
  425. utils.Expect(t, "[[0 21] [28]]", docs[0].TokenLocations)
  426. }