IndexBenchmark.vala 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /**
  2. * IndexBenchmark - Benchmarks for Index entity operations
  3. *
  4. * Measures performance of text index creation and search operations
  5. * using n-gram based full-text search.
  6. *
  7. * @version 0.1
  8. * @since 0.1
  9. */
  10. namespace Implexus.Tools.Perf {
  11. /**
  12. * Benchmark for Index entity operations.
  13. *
  14. * Tests:
  15. * - create_index: Creating text indices
  16. * - search_contains: Searching with contains pattern
  17. * - search_prefix: Prefix-based searches
  18. * - search_suffix: Suffix-based searches
  19. * - search_exact: Exact match searches
  20. * - search_rare_term: Searching for rare terms
  21. * - create_index_title: Creating indices on title field
  22. * - search_title: Searching on title index
  23. */
  24. public class IndexBenchmark : Benchmark {
  25. /**
  26. * {@inheritDoc}
  27. */
  28. public override string name { get { return "Index"; } }
  29. /**
  30. * Creates a new IndexBenchmark.
  31. *
  32. * @param engine The engine to benchmark
  33. * @param config The benchmark configuration
  34. */
  35. public IndexBenchmark(Core.Engine engine, BenchmarkConfig config) {
  36. base(engine, config);
  37. }
  38. /**
  39. * {@inheritDoc}
  40. */
  41. public override async void run_async(Results results) throws Error {
  42. // Setup: Create test documents with text content
  43. var parent_path = new Core.EntityPath("/perf-test/indices");
  44. yield ensure_container_async(new Core.EntityPath("/perf-test"), "perf-test");
  45. _cleanup_tracker.add_container(new Core.EntityPath("/perf-test").to_string());
  46. yield cleanup_path_async(parent_path);
  47. var root = yield _engine.get_root_async();
  48. var perf_test = yield root.get_child_async("perf-test");
  49. var parent_container = yield perf_test.create_container_async("indices");
  50. _cleanup_tracker.add_container(parent_path.to_string());
  51. int test_doc_count = _config.test_doc_count;
  52. int quick_iterations = _config.quick_iterations;
  53. int iterations = _config.iterations;
  54. // Sample texts for indexing
  55. string[] sample_texts = {
  56. "The quick brown fox jumps over the lazy dog",
  57. "A journey of a thousand miles begins with a single step",
  58. "To be or not to be that is the question",
  59. "All that glitters is not gold",
  60. "The only thing we have to fear is fear itself",
  61. "Ask not what your country can do for you",
  62. "I have a dream that one day this nation will rise up",
  63. "In the beginning was the Word and the Word was with God",
  64. "It was the best of times it was the worst of times",
  65. "Call me Ishmael Some years ago never mind how long precisely"
  66. };
  67. // Create test documents with text content
  68. print(" Setting up test documents (%d documents)...\n", test_doc_count);
  69. for (int i = 0; i < test_doc_count; i++) {
  70. var doc_name = "doc-%d".printf(i);
  71. var doc_path = parent_path.append_child(doc_name);
  72. yield cleanup_path_async(doc_path);
  73. var doc = yield parent_container.create_document_async(doc_name, "TextDoc");
  74. yield doc.set_entity_property_async(
  75. "content",
  76. new Invercargill.NativeElement<string>(sample_texts[i % sample_texts.length])
  77. );
  78. yield doc.set_entity_property_async(
  79. "title",
  80. new Invercargill.NativeElement<string>("Document %d".printf(i))
  81. );
  82. // Track for deferred cleanup
  83. _cleanup_tracker.add_document(doc_path.to_string());
  84. }
  85. // Test 1: Create index on content field
  86. var index_path = parent_path.append_child("content-index");
  87. print(" Testing create_index (%d iterations)...\n", quick_iterations);
  88. var create_op = new CreateIndexOp(this, parent_container, index_path, "content-index", "TextDoc", "content");
  89. var create_result = yield measure_async("create_index", quick_iterations, create_op);
  90. results.add(name, create_result);
  91. // Get the index entity for search tests
  92. Core.Entity? idx_entity = yield _engine.get_entity_or_null_async(index_path);
  93. var index_entity = idx_entity as Entities.Index;
  94. // Test 2: Search with single term (contains)
  95. print(" Testing search_contains (%d iterations)...\n", iterations);
  96. var contains_op = new SearchOp(index_entity, "*the*");
  97. var contains_result = yield measure_async("search_contains", iterations, contains_op);
  98. results.add(name, contains_result);
  99. // Test 3: Search with prefix pattern
  100. print(" Testing search_prefix (%d iterations)...\n", iterations);
  101. var prefix_op = new SearchOp(index_entity, "the*");
  102. var prefix_result = yield measure_async("search_prefix", iterations, prefix_op);
  103. results.add(name, prefix_result);
  104. // Test 4: Search with suffix pattern
  105. print(" Testing search_suffix (%d iterations)...\n", iterations);
  106. var suffix_op = new SearchOp(index_entity, "*ing");
  107. var suffix_result = yield measure_async("search_suffix", iterations, suffix_op);
  108. results.add(name, suffix_result);
  109. // Test 5: Exact match search
  110. print(" Testing search_exact (%d iterations)...\n", iterations);
  111. var exact_op = new SearchOp(index_entity, "dog");
  112. var exact_result = yield measure_async("search_exact", iterations, exact_op);
  113. results.add(name, exact_result);
  114. // Test 6: Search for rare term
  115. print(" Testing search_rare_term (%d iterations)...\n", iterations);
  116. var rare_op = new SearchOp(index_entity, "*Ishmael*");
  117. var rare_result = yield measure_async("search_rare_term", iterations, rare_op);
  118. results.add(name, rare_result);
  119. // Test 7: Create index on title field
  120. var title_index_path = parent_path.append_child("title-index");
  121. print(" Testing create_index_title (%d iterations)...\n", quick_iterations);
  122. var title_create_op = new CreateIndexOp(this, parent_container, title_index_path, "title-index", "TextDoc", "title");
  123. var title_create_result = yield measure_async("create_index_title", quick_iterations, title_create_op);
  124. results.add(name, title_create_result);
  125. // Test 8: Search on title index
  126. Core.Entity? title_idx_entity = yield _engine.get_entity_or_null_async(title_index_path);
  127. var title_index = title_idx_entity as Entities.Index;
  128. print(" Testing search_title (%d iterations)...\n", iterations);
  129. var title_search_op = new SearchOp(title_index, "*Document*");
  130. var title_search_result = yield measure_async("search_title", iterations, title_search_op);
  131. results.add(name, title_search_result);
  132. }
  133. }
  134. // Operation classes for IndexBenchmark
  135. private class CreateIndexOp : AsyncOperation {
  136. private IndexBenchmark _benchmark;
  137. private Core.Entity _parent_container;
  138. private Core.EntityPath _index_path;
  139. private string _name;
  140. private string _entity_type;
  141. private string _field_name;
  142. public CreateIndexOp(IndexBenchmark benchmark, Core.Entity parent_container, Core.EntityPath index_path, string name, string entity_type, string field_name) {
  143. _benchmark = benchmark;
  144. _parent_container = parent_container;
  145. _index_path = index_path;
  146. _name = name;
  147. _entity_type = entity_type;
  148. _field_name = field_name;
  149. }
  150. public override async void execute_async() throws Error {
  151. yield _benchmark.cleanup_path_async(_index_path);
  152. yield _parent_container.create_index_async(_name, _entity_type, _field_name);
  153. // Track for deferred cleanup
  154. _benchmark._cleanup_tracker.add_index(_index_path.to_string());
  155. }
  156. }
  157. private class SearchOp : AsyncOperation {
  158. private Entities.Index? _index_entity;
  159. private string _pattern;
  160. public SearchOp(Entities.Index? index_entity, string pattern) {
  161. _index_entity = index_entity;
  162. _pattern = pattern;
  163. }
  164. public override async void execute_async() throws Error {
  165. if (_index_entity != null) {
  166. // search is synchronous (runs in DBM thread context)
  167. var search_result = ((!) _index_entity).search(_pattern);
  168. if (search_result != null) {
  169. var children = yield ((!) search_result).get_children_async();
  170. int count = 0;
  171. foreach (var doc in children) {
  172. count++;
  173. }
  174. }
  175. }
  176. }
  177. }
  178. }