/ToMigrate/Raven.Tests/Indexes/HighlightTesting.cs

https://github.com/fitzchak/ravendb · C# · 436 lines · 388 code · 44 blank · 4 comment · 2 complexity · 0ad99b033cc4b72bb8c8801d571f1620 MD5 · raw file

  1. using System.Linq;
  2. using System.Text.RegularExpressions;
  3. using Raven.Abstractions.Indexing;
  4. using Raven.Client;
  5. using Raven.Client.Indexes;
  6. using Raven.Tests.Common;
  7. using Xunit;
  8. namespace Raven.Tests.Indexes
  9. {
  10. public class HighlightTesting : RavenTest
  11. {
  12. [Fact]
  13. public void HighlightText()
  14. {
  15. var item = new SearchItem
  16. {
  17. Id = "searchitems/1",
  18. Name = "This is a sample about a dog and his owner"
  19. };
  20. var searchFor = "about";
  21. using(var store = NewDocumentStore())
  22. using (var session = store.OpenSession())
  23. {
  24. session.Store(item);
  25. store.DatabaseCommands.PutIndex(new ContentSearchIndex().IndexName, new ContentSearchIndex().CreateIndexDefinition());
  26. session.SaveChanges();
  27. FieldHighlightings nameHighlighting;
  28. WaitForIndexing(store);
  29. var results = session.Advanced.DocumentQuery<SearchItem>("ContentSearchIndex")
  30. .WaitForNonStaleResults()
  31. .Highlight("Name", 128, 1, out nameHighlighting)
  32. .Search("Name", searchFor)
  33. .ToArray();
  34. Assert.NotEmpty(nameHighlighting.GetFragments("searchitems/1"));
  35. Assert.Equal("This is a sample <b style=\"background:yellow\">about</b> a dog and his owner",
  36. nameHighlighting.GetFragments("searchitems/1").First());
  37. }
  38. }
  39. [Fact]
  40. public void HighlightText_CutAfterDot()
  41. {
  42. var item = new SearchItem
  43. {
  44. Id = "searchitems/1",
  45. Name = "This is a. sample about a dog and his owner"
  46. };
  47. var searchFor = "about";
  48. using (var store = NewDocumentStore())
  49. using (var session = store.OpenSession())
  50. {
  51. session.Store(item);
  52. store.DatabaseCommands.PutIndex(new ContentSearchIndex().IndexName, new ContentSearchIndex().CreateIndexDefinition());
  53. session.SaveChanges();
  54. FieldHighlightings nameHighlighting;
  55. var results = session.Advanced.DocumentQuery<SearchItem>("ContentSearchIndex")
  56. .WaitForNonStaleResults()
  57. .Highlight("Name", 128, 1, out nameHighlighting)
  58. .Search("Name", searchFor)
  59. .ToArray();
  60. Assert.NotEmpty(nameHighlighting.GetFragments("searchitems/1"));
  61. Assert.Equal("sample <b style=\"background:yellow\">about</b> a dog and his owner",
  62. nameHighlighting.GetFragments("searchitems/1").First());
  63. }
  64. }
  65. [Fact]
  66. public void HighlightText_LineReturnedShorterThenOriginal()
  67. {
  68. var item = new SearchItem
  69. {
  70. Id = "searchitems/1",
  71. Name = "This is a sample about a dog and his owner"
  72. };
  73. var searchFor = "about";
  74. using (var store = NewDocumentStore())
  75. using (var session = store.OpenSession())
  76. {
  77. session.Store(item);
  78. store.DatabaseCommands.PutIndex(new ContentSearchIndex().IndexName, new ContentSearchIndex().CreateIndexDefinition());
  79. session.SaveChanges();
  80. FieldHighlightings nameHighlighting;
  81. var results = session.Advanced.DocumentQuery<SearchItem>("ContentSearchIndex")
  82. .WaitForNonStaleResults()
  83. .Highlight("Name", 20, 1, out nameHighlighting)
  84. .Search("Name", searchFor)
  85. .ToArray();
  86. Assert.NotEmpty(nameHighlighting.GetFragments("searchitems/1"));
  87. Assert.Equal("sample <b style=\"background:yellow\">about</b> a dog",
  88. nameHighlighting.GetFragments("searchitems/1").First());
  89. }
  90. }
  91. [Fact] public void HighlightText_CantFindWork()
  92. {
  93. var item = new SearchItem
  94. {
  95. Id = "searchitems/1",
  96. Name = "This is a sample about a dog and his owner"
  97. };
  98. var searchFor = "cat";
  99. using (var store = NewDocumentStore())
  100. using (var session = store.OpenSession())
  101. {
  102. session.Store(item);
  103. store.DatabaseCommands.PutIndex(new ContentSearchIndex().IndexName, new ContentSearchIndex().CreateIndexDefinition());
  104. session.SaveChanges();
  105. FieldHighlightings nameHighlighting;
  106. var results = session.Advanced.DocumentQuery<SearchItem>("ContentSearchIndex")
  107. .WaitForNonStaleResults()
  108. .Highlight("Name", 20, 1, out nameHighlighting)
  109. .Search("Name", searchFor)
  110. .ToArray();
  111. Assert.Empty(nameHighlighting.GetFragments("searchitems/1"));
  112. }
  113. }
  114. [Fact]
  115. public void HighlightText_FindAllReturences()
  116. {
  117. var item = new SearchItem
  118. {
  119. Id = "searchitems/1",
  120. Name = @"Once there lived a dog. He was very greedy. There were many times that he had to pay for his greed. Each time the dog promised himself, “I have learnt my lesson. Now I will never be greedy again.” But he soon forgot his promises and was as greedy as ever.
  121. One afternoon, the dog was terribly hungry. He decided to go look for something to eat. Just outside his house, there was a bridge. I will go and look for food on the other side of the bridge. The food there is definitely better, he thought to himself.
  122. He walked across the wooden bridge and started sniffing around for food. Suddenly, he spotted a bone lying at a distance. Ah, I am in luck. This looks a delicious bone, he said.
  123. Without wasting any time, the hungry dog picked up the bone and was just about to eat it, when he thought, Somebody might see here with this bone and then I will have to share it with them. So, I had better go home and eat it. Holding the bone in his mouth, he ran towards his house.
  124. While crossing the wooden bridge, the dog looked down into the river. There he saw his own reflection. The foolish dog mistook it for another dog. There is another dog in the water with bone in its mouth, he thought. Greedy, as he was, he thought, How nice it would be to snatch that piece of bone as well. Then, I will have two bones.
  125. So, the greedy dog looked at his reflection and growled. The reflection growled back, too. This made the dog angry. He looked down at his reflection and barked, Woof! Woof! As he opened his mouth, the bone in his mouth fell into the river. It was only when the water splashed that the greedy dog realized that what he had seen was nothing but his own reflections and not another dog. But it was too late. He had lost the piece of bone because of his greed. Now he had to go hungry."
  126. };
  127. var searchFor = "dog";
  128. using (var store = NewDocumentStore())
  129. using (var session = store.OpenSession())
  130. {
  131. session.Store(item);
  132. store.DatabaseCommands.PutIndex(new ContentSearchIndex().IndexName, new ContentSearchIndex().CreateIndexDefinition());
  133. session.SaveChanges();
  134. FieldHighlightings nameHighlighting;
  135. var results = session.Advanced.DocumentQuery<SearchItem>("ContentSearchIndex")
  136. .WaitForNonStaleResults()
  137. .Highlight("Name", 128, 20, out nameHighlighting)
  138. .Search("Name", searchFor)
  139. .ToArray();
  140. var fragments = nameHighlighting.GetFragments("searchitems/1");
  141. Assert.NotEmpty(fragments);
  142. int counter = 0;
  143. foreach (var fragment in fragments)
  144. {
  145. counter += Regex.Matches(fragment, "<b style=\"background").Count;
  146. }
  147. Assert.Equal(12, counter);
  148. }
  149. }
  150. [Fact]
  151. public void HighlightText_FindAllReturencesWithSeveralWords()
  152. {
  153. var item = new SearchItem
  154. {
  155. Id = "searchitems/1",
  156. Name =
  157. @"Once there lived a dog. He was very greedy. There were many times that he had to pay for his greed. Each time the dog promised himself, “I have learnt my lesson. Now I will never be greedy again.” But he soon forgot his promises and was as greedy as ever.
  158. One afternoon, the dog was terribly hungry. He decided to go look for something to eat. Just outside his house, there was a bridge. I will go and look for food on the other side of the bridge. The food there is definitely better, he thought to himself.
  159. He walked across the wooden bridge and started sniffing around for food. Suddenly, he spotted a bone lying at a distance. Ah, I am in luck. This looks a delicious bone, he said.
  160. Without wasting any time, the hungry dog picked up the bone and was just about to eat it, when he thought, Somebody might see here with this bone and then I will have to share it with them. So, I had better go home and eat it. Holding the bone in his mouth, he ran towards his house.
  161. While crossing the wooden bridge, the dog looked down into the river. There he saw his own reflection. The foolish dog mistook it for another dog. There is another dog in the water with bone in its mouth, he thought. Greedy, as he was, he thought, How nice it would be to snatch that piece of bone as well. Then, I will have two bones.
  162. So, the greedy dog looked at his reflection and growled. The reflection growled back, too. This made the dog angry. He looked down at his reflection and barked, Woof! Woof! As he opened his mouth, the bone in his mouth fell into the river. It was only when the water splashed that the greedy dog realized that what he had seen was nothing but his own reflections and not another dog. But it was too late. He had lost the piece of bone because of his greed. Now he had to go hungry."
  163. };
  164. var searchFor = "dog look";
  165. using (var store = NewDocumentStore())
  166. using (var session = store.OpenSession())
  167. {
  168. session.Store(item);
  169. store.DatabaseCommands.PutIndex(new ContentSearchIndex().IndexName, new ContentSearchIndex().CreateIndexDefinition());
  170. session.SaveChanges();
  171. FieldHighlightings nameHighlighting;
  172. var results = session.Advanced.DocumentQuery<SearchItem>("ContentSearchIndex")
  173. .WaitForNonStaleResults()
  174. .Highlight("Name", 128, 20, out nameHighlighting)
  175. .Search("Name", searchFor)
  176. .ToArray();
  177. var fragments = nameHighlighting.GetFragments("searchitems/1");
  178. Assert.NotEmpty(fragments);
  179. int counter = 0;
  180. foreach (var fragment in fragments)
  181. {
  182. counter += Regex.Matches(fragment, "<b style=\"background").Count;
  183. }
  184. Assert.Equal(14, counter);
  185. }
  186. }
  187. // this one passes now
  188. [Fact]
  189. public void HighlightText_WithProjection()
  190. {
  191. var item = new SearchItem
  192. {
  193. Id = "searchitems/1",
  194. Name = "This is a sample about a dog and his owner"
  195. };
  196. var searchFor = "about";
  197. using (var store = NewDocumentStore())
  198. using (var session = store.OpenSession())
  199. {
  200. session.Store(item);
  201. store.DatabaseCommands.PutIndex(new ContentSearchIndex().IndexName, new ContentSearchIndex().CreateIndexDefinition());
  202. session.SaveChanges();
  203. FieldHighlightings nameHighlighting;
  204. var results = session.Advanced.DocumentQuery<SearchItem>("ContentSearchIndex")
  205. .WaitForNonStaleResults()
  206. .Highlight("Name", 128, 1, out nameHighlighting)
  207. .Search("Name", searchFor)
  208. .SelectFields<SearchItemProjection>()
  209. .ToArray();
  210. Assert.Equal(1, results.Length);
  211. Assert.NotEmpty(nameHighlighting.GetFragments("searchitems/1"));
  212. Assert.Equal("This is a sample <b style=\"background:yellow\">about</b> a dog and his owner",
  213. nameHighlighting.GetFragments("searchitems/1").First());
  214. }
  215. }
  216. // this one passes now as well
  217. [Fact]
  218. public void HighlightText_WithProjectionQuery()
  219. {
  220. var item = new SearchItem
  221. {
  222. Id = "searchitems/1",
  223. Name = "This is a sample about a dog and his owner"
  224. };
  225. var searchFor = "about";
  226. using (var store = NewDocumentStore())
  227. using (var session = store.OpenSession())
  228. {
  229. session.Store(item);
  230. store.DatabaseCommands.PutIndex(new ContentSearchIndex().IndexName, new ContentSearchIndex().CreateIndexDefinition());
  231. session.SaveChanges();
  232. FieldHighlightings nameHighlighting = null;
  233. var results = session.Query<SearchItem>("ContentSearchIndex")
  234. .ProjectFromIndexFieldsInto<SearchItemProjection>()
  235. .Customize(x => x.WaitForNonStaleResults()
  236. .Highlight("Name", 128, 1, out nameHighlighting))
  237. .Search(x => x.Name, searchFor)
  238. .ToArray();
  239. Assert.Equal(1, results.Length);
  240. Assert.NotEmpty(nameHighlighting.GetFragments("searchitems/1"));
  241. Assert.Equal("This is a sample <b style=\"background:yellow\">about</b> a dog and his owner",
  242. nameHighlighting.GetFragments("searchitems/1").First());
  243. }
  244. }
  245. // this one fails
  246. [Fact]
  247. public void HighlightText_WithMapReduce()
  248. {
  249. var item1 = new SearchItemWithType
  250. {
  251. Id = "searchitems/1",
  252. Type = "Fact",
  253. Text = "Once there lived a dog."
  254. };
  255. var item2 = new SearchItemWithType
  256. {
  257. Id = "searchitems/2",
  258. Type = "Opinion",
  259. Text = "The dog was very greedy."
  260. };
  261. var item3 = new SearchItemWithType
  262. {
  263. Id = "searchitems/3",
  264. Type = "Opinion",
  265. Text = "He had lost the piece of dog bone because of his greed."
  266. };
  267. var searchFor = "dog";
  268. using (var store = NewDocumentStore())
  269. using (var session = store.OpenSession())
  270. {
  271. session.Store(item1);
  272. session.Store(item2);
  273. session.Store(item3);
  274. store.DatabaseCommands.PutIndex(new ContentSearchMapReduceIndex().IndexName, new ContentSearchMapReduceIndex().CreateIndexDefinition());
  275. session.SaveChanges();
  276. FieldHighlightings nameHighlighting;
  277. var results = session.Advanced.DocumentQuery<SearchItemWithTypeResult>("ContentSearchMapReduceIndex")
  278. .WaitForNonStaleResults()
  279. .Highlight("AllText", "Type", 128, 1, out nameHighlighting)
  280. .Search("AllText", searchFor)
  281. .ToArray();
  282. Assert.Equal(2, results.Length);
  283. var opinionFragments = nameHighlighting.GetFragments("Opinion");
  284. Assert.Equal(1, opinionFragments.Length);
  285. Assert.Equal("The <b style=\"background:yellow\">dog</b> was very greedy. He had lost the piece of <b style=\"background:yellow\">dog</b> bone because of his greed.", opinionFragments[0]);
  286. var factFragments = nameHighlighting.GetFragments("Fact");
  287. Assert.Equal(1, factFragments.Length);
  288. Assert.Equal("Once there lived a <b style=\"background:yellow\">dog</b>.", factFragments[0]);
  289. }
  290. }
  291. // this one passes
  292. [Fact]
  293. public void HighlightText_WithMapReduceWithFragments()
  294. {
  295. var item1 = new SearchItemWithType
  296. {
  297. Id = "searchitems/1",
  298. Type = "Fact",
  299. Text = "Once there lived a dog."
  300. };
  301. var item2 = new SearchItemWithType
  302. {
  303. Id = "searchitems/2",
  304. Type = "Opinion",
  305. Text = "The dog was very greedy."
  306. };
  307. var item3 = new SearchItemWithType
  308. {
  309. Id = "searchitems/3",
  310. Type = "Opinion",
  311. Text = "He had lost the piece of dog bone because of his greed."
  312. };
  313. var searchFor = "dog";
  314. using (var store = NewDocumentStore())
  315. using (var session = store.OpenSession())
  316. {
  317. session.Store(item1);
  318. session.Store(item2);
  319. session.Store(item3);
  320. store.DatabaseCommands.PutIndex(new ContentSearchMapReduceIndex().IndexName, new ContentSearchMapReduceIndex().CreateIndexDefinition());
  321. session.SaveChanges();
  322. var results = session.Advanced.DocumentQuery<SearchItemWithTypeResultWithFragments>("ContentSearchMapReduceIndex")
  323. .WaitForNonStaleResults()
  324. .Highlight("AllText", 128, 1, "Fragments")
  325. .Search("AllText", searchFor)
  326. .ToArray();
  327. Assert.Equal(2, results.Length);
  328. var opinionResult = results.First(r => r.Type == "Opinion");
  329. var opinionFragments = opinionResult.Fragments;
  330. Assert.Equal(1, opinionFragments.Length);
  331. Assert.Equal("The <b style=\"background:yellow\">dog</b> was very greedy. He had lost the piece of <b style=\"background:yellow\">dog</b> bone because of his greed.", opinionFragments[0]);
  332. var factResult = results.First(r => r.Type == "Fact");
  333. var factFragments = factResult.Fragments;
  334. Assert.Equal(1, factFragments.Length);
  335. Assert.Equal("Once there lived a <b style=\"background:yellow\">dog</b>.", factFragments[0]);
  336. }
  337. }
  338. }
  339. public class ContentSearchIndex : AbstractIndexCreationTask<SearchItem>
  340. {
  341. public ContentSearchIndex()
  342. {
  343. Map = (docs => from doc in docs
  344. select new {doc.Name});
  345. Index(x => x.Name, FieldIndexing.Analyzed);
  346. Store(x => x.Name, FieldStorage.Yes);
  347. TermVector(x => x.Name, FieldTermVector.WithPositionsAndOffsets);
  348. }
  349. }
  350. public class SearchItem
  351. {
  352. public string Name { get; set; }
  353. public string Id { get; set; }
  354. }
  355. public class SearchItemProjection
  356. {
  357. public string Name { get; set; }
  358. public string Id { get; set; }
  359. }
  360. public class ContentSearchMapReduceIndex : AbstractIndexCreationTask<SearchItemWithType, SearchItemWithTypeResult>
  361. {
  362. public ContentSearchMapReduceIndex()
  363. {
  364. Map = (docs => from doc in docs
  365. select new { doc.Type, AllText = doc.Text, Count = 1 });
  366. Reduce = (results => from result in results
  367. group result by result.Type
  368. into g
  369. select new { Type = g.Key, AllText = string.Join(" ", g.Select(r => r.AllText)), Count = g.Sum(r => r.Count) });
  370. Index(x => x.AllText, FieldIndexing.Analyzed);
  371. Store(x => x.AllText, FieldStorage.Yes);
  372. Store(x => x.Type, FieldStorage.Yes);
  373. TermVector(x => x.AllText, FieldTermVector.WithPositionsAndOffsets);
  374. }
  375. }
  376. public class SearchItemWithType
  377. {
  378. public string Type { get; set; }
  379. public string Text { get; set; }
  380. public string Id { get; set; }
  381. }
  382. public class SearchItemWithTypeResult
  383. {
  384. public string Type { get; set; }
  385. public string AllText { get; set; }
  386. public int Count { get; set; }
  387. }
  388. public class SearchItemWithTypeResultWithFragments : SearchItemWithTypeResult
  389. {
  390. public string[] Fragments { get; set; }
  391. }
  392. }