Raptor 4.0.0-rc.1
A fast and space-efficient pre-filter
Loading...
Searching...
No Matches
search_partitioned_hibf.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2006-2026 Knut Reinert & Freie Universität Berlin
2// SPDX-FileCopyrightText: 2016-2026 Knut Reinert & MPI für molekulare Genetik
3// SPDX-License-Identifier: BSD-3-Clause
4
10#pragma once
11
12#include <seqan3/search/views/minimiser_hash.hpp>
13
14#include <hibf/contrib/std/chunk_view.hpp>
15
22
23namespace raptor
24{
25
26template <typename index_t>
27void search_partitioned_hibf(search_arguments const & arguments, index_t && index)
28{
29 seqan3::sequence_file_input<dna4_traits, seqan3::fields<seqan3::field::id, seqan3::field::seq>> fin{
30 arguments.query_file};
31 using record_type = typename decltype(fin)::record_type;
32
34
35 sync_out synced_out{arguments};
36
37 std::vector<std::string> results; // cache results since we are searching multiple hibfs
38
39 raptor::threshold::threshold const thresholder{arguments.make_threshold_parameters()};
40
41 // PHIBF indices have local bin path indices which must be converted to global ones
42 size_t bin_path_index_offset{0};
43
44 // searching with storing all results in results map
45 auto worker = [&](size_t const start, size_t const extent, bool const output_results)
46 {
47 seqan::hibf::serial_timer local_compute_minimiser_timer{};
48 seqan::hibf::serial_timer local_query_ibf_timer{};
49 seqan::hibf::serial_timer local_generate_results_timer{};
50
51 auto agent = index.ibf().membership_agent();
52
53 std::string result_string{};
54 std::vector<uint64_t> minimiser;
55
56 auto hash_adaptor = seqan3::views::minimiser_hash(arguments.shape,
57 seqan3::window_size{arguments.window_size},
58 seqan3::seed{adjust_seed(arguments.shape_weight)});
59
60 for (size_t pos = start; pos < start + extent; ++pos)
61 {
62 auto const & seq = records[pos].sequence();
63 std::string & result_string = results[pos];
64
65 auto minimiser_view = seq | hash_adaptor | std::views::common;
66 local_compute_minimiser_timer.start();
67 minimiser.assign(minimiser_view.begin(), minimiser_view.end());
68 local_compute_minimiser_timer.stop();
69
70 size_t const minimiser_count{minimiser.size()};
71 size_t const threshold = thresholder.get(minimiser_count);
72
73 local_query_ibf_timer.start();
74 auto & result = agent.membership_for(minimiser, threshold); // Results contains user bin IDs
75 local_query_ibf_timer.stop();
76 local_generate_results_timer.start();
77 for (auto && user_bin_id : result)
78 {
79 result_string += std::to_string(bin_path_index_offset + user_bin_id);
80 result_string += ',';
81 }
82
83 if (output_results)
84 {
85 result_string.insert(result_string.begin(), '\t');
86 auto const & id = records[pos].id();
87 result_string.insert(result_string.begin(), id.begin(), id.end());
88
89 if (auto & last_char = result_string.back(); last_char == ',')
90 last_char = '\n';
91 else
92 result_string += '\n';
93
94 synced_out.write(result_string);
95 result_string.clear(); // free memory
96 }
97 local_generate_results_timer.stop();
98 }
99
100 arguments.compute_minimiser_timer += local_compute_minimiser_timer;
101 arguments.query_ibf_timer += local_query_ibf_timer;
102 arguments.generate_results_timer += local_generate_results_timer;
103 };
104
105 bool first_chunk{true};
106 auto bin_paths = arguments.bin_path; // keep local list since arguments is immutable
107 std::vector<size_t> bin_path_index_offsets(arguments.parts, 0);
108
109 for (auto && chunked_records : fin | seqan::stl::views::chunk((1ULL << 20) * 10))
110 {
111 // prefetch the first partition while query IO is done
112 auto cereal_future = std::async(std::launch::async,
113 [&]()
114 {
115 load_index(index, arguments, 0);
116 });
117
118 records.clear();
119 arguments.query_file_io_timer.start();
120 std::ranges::move(chunked_records, std::back_inserter(records));
121 arguments.query_file_io_timer.stop();
122
123 results.resize(records.size());
124
125 cereal_future.get();
126
127 assert(arguments.parts > 0);
128 for (int part = 0; part < arguments.parts - 1; ++part)
129 {
130 do_parallel(worker, records.size(), arguments.threads, false /*do not write results*/);
131 load_index(index, arguments, part + 1);
132 if (first_chunk)
133 {
134 bin_path_index_offsets[part + 1] = bin_paths.size();
135 bin_paths.insert(bin_paths.end(), index.bin_path().begin(), index.bin_path().end());
136 }
137 bin_path_index_offset = bin_path_index_offsets[part + 1];
138 }
139
140 if (first_chunk)
141 {
142 auto arguments_copy = arguments;
143 arguments_copy.bin_path = bin_paths;
144 synced_out.write_header(arguments_copy, index.ibf().ibf_vector[0].hash_function_count());
145 }
146 do_parallel(worker, records.size(), arguments.threads, true /*write results*/);
147
148 first_chunk = false;
149 bin_path_index_offset = 0;
150 }
151}
152
153} // namespace raptor
Provides raptor::adjust_seed.
T async(T... args)
T back(T... args)
T back_inserter(T... args)
T begin(T... args)
Definition threshold.hpp:19
T clear(T... args)
Provides raptor::dna4_traits.
Provides raptor::do_parallel.
T insert(T... args)
Provides raptor::load_index.
T move(T... args)
T resize(T... args)
Provides raptor::sync_out.
Provides raptor::threshold::threshold.
T to_string(T... args)
Hide me