xapian-core  2.1.0
honey_inverter.cc
Go to the documentation of this file.
1 
4 /* Copyright (C) 2009,2013,2024,2026 Olly Betts
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see
18  * <https://www.gnu.org/licenses/>.
19  */
20 
21 #include <config.h>
22 
23 #include "honey_inverter.h"
24 
25 #include "honey_positionlist.h"
26 #include "honey_postlist.h"
27 #include "honey_postlisttable.h"
28 
29 #include "api/termlist.h"
30 
31 #include <map>
32 #include <string>
33 
34 using namespace std;
35 
36 void
38  Xapian::docid did,
39  string_view term,
40  const Xapian::VecCOW<Xapian::termpos>& posvec,
41  bool modifying)
42 {
43  string s;
44  position_table.pack(s, posvec);
45  if (modifying && has_positions_cache != 0) {
46  // If we add positions we must then have positions, but if we remove
47  // positions we don't know if we then have them or not.
48  has_positions_cache = s.empty() ? -1 : 1;
49 
50  auto i = pos_changes.find(term);
51  if (i != pos_changes.end()) {
52  map<Xapian::docid, string>& m = i->second;
53  auto j = m.find(did);
54  if (j != m.end()) {
55  // Update existing entry.
56  swap(j->second, s);
57  return;
58  }
59  }
60  const string& key = position_table.make_key(did, term);
61  string old_tag;
62  if (position_table.get_exact_entry(key, old_tag) && s == old_tag) {
63  // Identical to existing entry on disk.
64  return;
65  }
66  } else {
67  // If we add positions, we must then have positions.
68  if (!s.empty()) has_positions_cache = 1;
69  }
70  set_positionlist(did, term, s);
71 }
72 
73 void
75  Xapian::docid did,
76  string_view term,
77  const Xapian::TermIterator& term_it,
78  bool modifying)
79 {
80  auto ptr = term_it.internal->get_vec_termpos();
81  if (ptr) {
82  if (!ptr->empty()) {
83  store_positions(position_table, did, term, *ptr, modifying);
84  return;
85  }
86  } else {
88  if (pos != term_it.positionlist_end()) {
90  posvec.reserve(pos.internal->get_approx_size());
91  while (pos != term_it.positionlist_end()) {
92  posvec.push_back(*pos);
93  ++pos;
94  }
95  store_positions(position_table, did, term, posvec, modifying);
96  return;
97  }
98  }
99  // If we get here, the new position list was empty.
100  if (modifying)
101  delete_positionlist(did, term);
102 }
103 
104 void
106  string_view term,
107  string_view s)
108 {
109  has_positions_cache = s.empty() ? -1 : 1;
110  pos_changes.insert(make_pair(term, map<Xapian::docid, string>()))
111  .first->second[did] = s;
112 }
113 
114 void
116  string_view term)
117 {
118  set_positionlist(did, term, {});
119 }
120 
121 bool
123  string_view term,
124  string& s) const
125 {
126  auto i = pos_changes.find(term);
127  if (i == pos_changes.end())
128  return false;
129  const map<Xapian::docid, string>& m = i->second;
130  auto j = m.find(did);
131  if (j == m.end())
132  return false;
133  s = j->second;
134  return true;
135 }
136 
137 bool
139 {
140  if (has_positions_cache < 0) {
141  // FIXME: Can we cheaply keep track of some things to make this more
142  // efficient? E.g. how many sets and deletes we had in total perhaps.
143  honey_tablesize_t changes = 0;
144  for (const auto& i : pos_changes) {
145  const map<Xapian::docid, string>& m = i.second;
146  for (const auto& j : m) {
147  const string& s = j.second;
148  if (!s.empty())
149  return true;
150  ++changes;
151  }
152  }
153 
154  // We have positions unless all the existing entries are removed.
155  has_positions_cache = (changes != position_table.get_entry_count());
156  }
157  return has_positions_cache;
158 }
159 
160 void
162 {
163  table.merge_doclen_changes(doclen_changes);
164  doclen_changes.clear();
165 }
166 
167 void
169 {
170  auto i = postlist_changes.find(term);
171  if (i == postlist_changes.end()) return;
172 
173  // Flush buffered changes for just this term's postlist.
174  table.merge_changes(term, i->second);
175  postlist_changes.erase(i);
176 }
177 
178 void
180 {
181  for (auto&& i : postlist_changes) {
182  table.merge_changes(i.first, i.second);
183  }
184  postlist_changes.clear();
185 }
186 
187 void
189 {
190  if (pfx.empty())
191  return flush_all_post_lists(table);
192 
193  auto begin = postlist_changes.lower_bound(pfx);
194  decltype(begin) end;
195  string pfxinc{pfx};
196  while (true) {
197  if (pfxinc.back() != '\xff') {
198  ++pfxinc.back();
199  end = postlist_changes.lower_bound(pfxinc);
200  break;
201  }
202  pfxinc.resize(pfxinc.size() - 1);
203  if (pfxinc.empty()) {
204  end = postlist_changes.end();
205  break;
206  }
207  }
208 
209  for (auto i = begin; i != end; ++i) {
210  table.merge_changes(i->first, i->second);
211  }
212 
213  // Erase all the entries in one go, as that's:
214  // O(log(postlist_changes.size()) + O(number of elements removed)
215  postlist_changes.erase(begin, end);
216 }
217 
218 void
220 {
221  flush_doclengths(table);
222  flush_all_post_lists(table);
223 }
224 
225 void
227 {
228  for (auto i : pos_changes) {
229  const string& term = i.first;
230  const map<Xapian::docid, string>& m = i.second;
231  for (auto j : m) {
232  Xapian::docid did = j.first;
233  const string& s = j.second;
234  if (!s.empty())
235  table.set_positionlist(did, term, s);
236  else
237  table.delete_positionlist(did, term);
238  }
239  }
240  pos_changes.clear();
241  has_positions_cache = -1;
242 }
void delete_positionlist(Xapian::docid did, std::string_view term)
bool get_positionlist(Xapian::docid did, std::string_view term, std::string &s) const
void store_positions(const HoneyPositionTable &position_table, Xapian::docid did, std::string_view term, const Xapian::VecCOW< Xapian::termpos > &posvec, bool modifying)
bool has_positions(const HoneyPositionTable &position_table) const
void flush_pos_lists(HoneyPositionTable &table)
Flush position changes.
void flush(HoneyPostListTable &table)
Flush all postlist table changes.
void flush_post_list(HoneyPostListTable &table, std::string_view term)
Flush postlist changes for term.
void set_positionlist(Xapian::docid did, std::string_view term, std::string_view s)
void flush_all_post_lists(HoneyPostListTable &table)
Flush postlist changes for all terms.
void flush_doclengths(HoneyPostListTable &table)
Flush document length changes.
void flush_post_lists(HoneyPostListTable &table, std::string_view pfx)
Flush postlist changes for all terms which start with pfx.
static std::string make_key(Xapian::docid did, std::string_view term)
void set_positionlist(Xapian::docid did, std::string_view term, std::string_view s)
Set the position list for term term in document did.
void pack(std::string &s, const Xapian::VecCOW< Xapian::termpos > &vec) const
Pack a position list into a string.
void delete_positionlist(Xapian::docid did, std::string_view term)
Delete the position list for term term in document did.
void merge_changes(std::string_view term, const HoneyInverter::PostingChanges &changes)
void merge_doclen_changes(const std::map< Xapian::docid, Xapian::termcount > &changes)
bool get_exact_entry(std::string_view key, std::string *tag) const
Definition: honey_table.cc:247
honey_tablesize_t get_entry_count() const
Definition: honey_table.h:693
Class for iterating over term positions.
virtual const Xapian::VecCOW< Xapian::termpos > * get_vec_termpos() const
Get pointer to VecCOW<termpos> if that's the internal representation.
Definition: termlist.cc:42
Class for iterating over a list of terms.
Definition: termiterator.h:41
PositionIterator positionlist_end() const noexcept
Return an end PositionIterator for the current term.
Definition: termiterator.h:109
PositionIterator positionlist_begin() const
Return a PositionIterator for the current term.
Suitable for "simple" type T.
Definition: smallvector.h:62
void reserve(size_type n)
Definition: smallvector.h:147
void push_back(T elt)
Definition: smallvector.h:190
string term
Xapian::termpos pos
unsigned long long honey_tablesize_t
How many entries there are in a table.
Definition: honey_defs.h:107
HoneyInverter class which "inverts the file".
A position list in a honey database.
PostList in a honey database.
Subclass of HoneyTable which holds postlists.
unsigned XAPIAN_DOCID_BASE_TYPE docid
A unique identifier for a document.
Definition: types.h:51
Abstract base class for termlists.