casacore
Loading...
Searching...
No Matches
ColumnsIndex.h
Go to the documentation of this file.
1// # ColumnsIndex.h: Index to one or more columns in a table
2// # Copyright (C) 1998,1999,2001,2002
3// # Associated Universities, Inc. Washington DC, USA.
4// #
5// # This library is free software; you can redistribute it and/or modify it
6// # under the terms of the GNU Library General Public License as published by
7// # the Free Software Foundation; either version 2 of the License, or (at your
8// # option) any later version.
9// #
10// # This library is distributed in the hope that it will be useful, but WITHOUT
11// # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12// # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13// # License for more details.
14// #
15// # You should have received a copy of the GNU Library General Public License
16// # along with this library; if not, write to the Free Software Foundation,
17// # Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18// #
19// # Correspondence concerning AIPS++ should be addressed as follows:
20// # Internet email: casa-feedback@nrao.edu.
21// # Postal address: AIPS++ Project Office
22// # National Radio Astronomy Observatory
23// # 520 Edgemont Road
24// # Charlottesville, VA 22903-2475 USA
25
26#ifndef TABLES_COLUMNSINDEX_H
27#define TABLES_COLUMNSINDEX_H
28
29// # Includes
30#include <casacore/casa/aips.h>
31#include <casacore/tables/Tables/Table.h>
32#include <casacore/casa/Arrays/Vector.h>
33#include <casacore/casa/Containers/Block.h>
34#include <casacore/casa/Containers/Record.h>
35
36namespace casacore { // # NAMESPACE CASACORE - BEGIN
37
38// # Forward Declarations
39class String;
40class TableColumn;
41template <typename T>
43
44// <summary>
45// Index to one or more columns in a table.
46// </summary>
47
48// <use visibility=export>
49
50// <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="tColumnsIndex.cc" demos="">
51// </reviewed>
52
53// <prerequisite>
54// <li> <linkto class=Table>Table</linkto>
55// <li> <linkto class=Record>Record</linkto>
56// <li> <linkto class=RecordFieldPtr>RecordFieldPtr</linkto>
57// </prerequisite>
58
59// <synopsis>
60// This class makes it possible to use transient indices on top
61// of tables in order to speed up the process of finding rows
62// based on a given key or key range.
63// When constructing a <src>ColumnsIndex</src> object, one has to define
64// which columns form the key for this index on the given
65// <src>table</src> object.
66// Only scalar columns are supported. The data in the given columns
67// will be read, sorted (if needed), and stored in memory.
68// When looking up a key or key range, the class will use a fast binary
69// search on the data held in memory.
70// <p>
71// The <src>ColumnsIndex</src> object contains a
72// <linkto class=Record>Record</linkto> object which can be used
73// to define the key to be looked up. The record contains a field for
74// each column in the index (with the same name and data type).
75// The fastest way to fill the key is by creating a
76// <linkto class=RecordFieldPtr>RecordFieldPtr</linkto> object for
77// each field in the record (see the example) and fill it as needed.
78// However, one can also use the <src>Record::define</src> function,
79// but that is slower.
80// <br>
81// A second record is available to define the upper key
82// when a key range has to be looked up. The keys can be accessed
83// using the various <src>accessKey</src> functions.
84// <p>
85// When a key is defined, the <src>getRowNumbers</src> function can be
86// used to find the table rows containing the given key (range).
87// Function <src>getRowNumber</src> can be used if all keys in the index
88// are unique (which can be tested with the <src>isUnique</src> function).
89// <p>
90// Instead of using the internal records holding the keys, one can also
91// pass its own Record object to <src>getRowNumbers</src>.
92// However, it will be slower.
93// <p>
94// When constructing the object, the user can supply his own compare
95// function. The default compare function compares each field of the
96// key in the normal way. A user's compare function makes it possible
97// to compare in a special way. E.g. one could use near instead of ==
98// on floating point fields. Another example (which is shown in one
99// of the examples below) makes it possible to find a key in an
100// index consisting of a time and width.
101// <p>
102// After an index is created, it is possible to change the data
103// in the underlying columns. However, the <src>ColumnsIndex</src> can
104// not detect if the column data have changed. It can only detect if
105// the number of rows has changed. If the column data have changed,
106// the user has to use the <src>setChanged</src> function to indicate
107// that all columns or a particular column has changed.
108// <br>If data have changed, the entire index will be recreated by
109// rereading and optionally resorting the data. This will be deferred
110// until the next key lookup.
111// </synopsis>
112
113// <example>
114// Suppose one has an antenna table with key ANTENNA.
115// <srcblock>
116// // Open the table and make an index for column ANTENNA.
117// Table tab("antenna.tab")
118// ColumnsIndex colInx(tab, "ANTENNA");
119// // Make a RecordFieldPtr for the ANTENNA field in the index key record.
120// // Its data type has to match the data type of the column.
121// RecordFieldPtr<Int> antFld(colInx.accessKey(), "ANTENNA");
122// // Now loop in some way and find the row for the antenna
123// // involved in that loop.
124// Bool found;
125// while (...) {
126// // Fill the key field and get the row number.
127// // ANTENNA is a unique key, so only one row number matches.
128// // Otherwise function getRowNumbers had to be used.
129// *antFld = antenna;
130// rownr_t antRownr = colInx.getRowNumber (found);
131// if (!found) {
132// cout << "Antenna " << antenna << " is unknown" << endl;
133// } else {
134// // antRownr can now be used to get data from that row in
135// // the antenna table.
136// }
137// }
138// </srcblock>
139//
140// The following example shows how multiple keys can be used and how
141// a search on a range can be done.
142// <srcblock>
143// Table tab("sometable")
144// // Note that TIME is the main key.
145// // Also note that stringToVector (in ArrayUtil.h) is a handy
146// // way to convert a String to a Vector<String>.
147// ColumnsIndex colInx(tab, stringToVector("TIME,ANTENNA"));
148// // Make a RecordFieldPtr for the fields in lower and upper key records.
149// RecordFieldPtr<Double> timeLow(colInx.accessLowerKey(), "TIME");
150// RecordFieldPtr<Int> antLow(colInx.accessLowerKey(), "ANTENNA");
151// RecordFieldPtr<Double> timeUpp(colInx.accessUpperKey(), "TIME");
152// RecordFieldPtr<Int> antUpp(colInx.accessUpperKey(), "ANTENNA");
153// while (...) {
154// // Fill the key fields.
155// *timeLow = ...;
156// *antLow = ...;
157// *timeUpp = ...;
158// *antUpp = ...;
159// // Find the row numbers for keys between low and upp (inclusive).
160// RowNumbers rows = colInx.getRowNumbers (True, True);
161// }
162// </srcblock>
163//
164// The following example shows how a specific compare function
165// could look like. A function like this will actually be used in the
166// calibration software.
167// <br>
168// The table for which the index is built, has rows with the TIME as its key.
169// However, each row is valid for a given interval, where TIME gives
170// the middle of the interval and WIDTH the length of the interval.
171// This means that the compare function has to test whether the key
172// is part of the interval.
173// <srcblock>
174// Int myCompare (const Block<void*>& fieldPtrs,
175// const Block<void*>& dataPtrs,
176// const Block<Int>& dataTypes,
177// rownr_t index)
178// {
179// // Assert (for performance only in debug mode) that the correct
180// // fields are used.
181// DebugAssert (dataTypes.nelements() == 2, AipsError);
182// DebugAssert (dataTypes[0] == TpDouble && dataTypes[1] == TpDouble,
183// AipsError);
184// // Now get the key to be looked up
185// // (an awfully looking cast has to be used).
186// const Double key = *(*(const RecordFieldPtr<Double>*)(fieldPtrs[0]));
187// // Get the time and width of the entry to be compared.
188// const Double time = ((const Double*)(dataPtrs[0]))[index];
189// const Double width = ((const Double*)(dataPtrs[1]))[index];
190// const Double start = time - width/2;
191// const Double end = time + width/2;
192// // Test if the key is before, after, or in the interval
193// // (representing less, greater, equal).
194// if (key < start) {
195// return -1;
196// } else if (key > end) {
197// return 1;
198// }
199// return 0;
200// }
201//
202// // Now use this compare function in an actual index.
203// Table tab("sometable")
204// ColumnsIndex colInx(tab, stringToVector("TIME,WIDTH"), myCompare);
205// // Make a RecordFieldPtr for the TIME field in the key record.
206// // Note that although the WIDTH is part of the index, it is
207// // not an actual key. So it does not need to be filled in.
208// RecordFieldPtr<Double> time(colInx.accessLowerKey(), "TIME");
209// Bool found;
210// while (...) {
211// // Fill the key field.
212// *time = ...;
213// // Find the row number for this time.
214// rownr_t rownr = colInx.getRowNumber (found);
215// }
216// </srcblock>
217// </example>
218
219// <motivation>
220// The calibration software needs to lookup keys in calibration tables
221// very frequently. This class makes that process much easier and faster.
222// </motivation>
223
225 public:
226 // Define the signature of a comparison function.
227 // The first block contains pointers to <src>RecordFieldPtr<T></src>
228 // objects holding the key to be looked up.
229 // The second block contains pointers to the column data.
230 // The <src>index</src> argument gives the index in the column data.
231 // The third block contains data types of those blocks (TpBool, etc.).
232 // The function should return -1 if key is less than data,
233 // 0 if equal, 1 if greater.
234 // <br>An example above shows how a compare function can be used.
235 typedef Int Compare(const Block<void*>& fieldPtrs, const Block<void*>& dataPtrs,
236 const Block<Int>& dataTypes, rownr_t index);
237
238 // Create an index on the given table for the given column.
239 // The column has to be a scalar column.
240 // If <src>noSort==True</src>, the table is already in order of that
241 // column and the sort step will not be done.
242 // The default compare function is provided by this class. It simply
243 // compares each field in the key.
244 ColumnsIndex(const Table&, const String& columnName, Compare* compareFunction = 0,
245 Bool noSort = False);
246
247 // Create an index on the given table for the given columns, thus
248 // the key is formed by multiple columns.
249 // The columns have to be scalar columns.
250 // If <src>noSort==True</src>, the table is already in order of those
251 // columns and the sort step will not be done.
252 // The default compare function is provided by this class. It simply
253 // compares each field in the key.
254 ColumnsIndex(const Table&, const Vector<String>& columnNames, Compare* compareFunction = 0,
255 Bool noSort = False);
256
257 // Copy constructor (copy semantics).
259
261
262 // Assignment (copy semantics).
264
265 // Are all keys in the index unique?
266 Bool isUnique() const;
267
268 // Return the names of the columns forming the index.
270
271 // Get the table for which this index is created.
272 const Table& table() const;
273
274 // Something has changed in the table, so the index has to be recreated.
275 // The 2nd version indicates that a specific column has changed,
276 // so only that column is reread. If that column is not part of the
277 // index, nothing will be done.
278 // <br>Note that the class itself is keeping track if the number of
279 // rows in the table changes.
280 // <group>
282 void setChanged(const String& columnName);
283 // </group>
284
285 // Access the key values.
286 // These functions allow you to create RecordFieldPtr<T> objects
287 // for each field in the key. In this way you can quickly fill in
288 // the key.
289 // <br>The records have a fixed type, so you cannot add or delete fields.
290 // <group>
291 Record& accessKey();
294 // </group>
295
296 // Find the row number matching the key. All keys have to be unique,
297 // otherwise an exception is thrown.
298 // If no match is found, <src>found</src> is set to False.
299 // The 2nd version makes it possible to pass in your own Record
300 // instead of using the internal record via the <src>accessKey</src>
301 // functions. Note that the given Record will be copied to the internal
302 // record, thus overwrites it.
303 // <group>
305 rownr_t getRowNumber(Bool& found, const Record& key);
306 // </group>
307
308 // Find the row numbers matching the key. It should be used instead
309 // of <src>getRowNumber</src> if the same key can exist multiple times.
310 // The 2nd version makes it possible to pass in your own Record
311 // instead of using the internal record via the <src>accessKey</src>
312 // functions. Note that the given Record will be copied to the internal
313 // record, thus overwrites it.
314 // <group>
317 // </group>
318
319 // Find the row numbers matching the key range. The boolean arguments
320 // tell if the lower and upper key are part of the range.
321 // The 2nd version makes it possible to pass in your own Records
322 // instead of using the internal records via the
323 // <src>accessLower/UpperKey</src> functions.
324 // Note that the given Records will be copied to the internal
325 // records, thus overwrite them.
326 // <group>
327 RowNumbers getRowNumbers(Bool lowerInclusive, Bool upperInclusive);
328 RowNumbers getRowNumbers(const Record& lower, const Record& upper, Bool lowerInclusive,
329 Bool upperInclusive);
330 // </group>
331
332 // Fill the internal key field from the corresponding external key.
333 // The data type may differ.
334 static void copyKeyField(void* field, int dtype, const Record& key);
335
336 protected:
337 // Copy that object to this.
338 void copy(const ColumnsIndex& that);
339
340 // Delete all data in the object.
342
343 // Add a column to the record description for the keys.
345
346 // Create the various members in the object.
347 void create(const Table& table, const Vector<String>& columnNames, Compare* compareFunction,
348 Bool noSort);
349
350 // Make the various internal <src>RecordFieldPtr</src> objects.
352
353 // Read the data of the columns forming the index, sort them and
354 // form the index.
355 void readData();
356
357 // Do a binary search on <src>itsUniqueIndex</src> for the key in
358 // <src>fieldPtrs</src>.
359 // If the key is found, <src>found</src> is set to True and the index
360 // in <src>itsUniqueIndex</src> is returned.
361 // If not found, <src>found</src> is set to False and the index
362 // of the next higher key is returned.
363 rownr_t bsearch(Bool& found, const Block<void*>& fieldPtrs) const;
364
365 // Compare the key in <src>fieldPtrs</src> with the given index entry.
366 // -1 is returned when less, 0 when equal, 1 when greater.
367 static Int compare(const Block<void*>& fieldPtrs, const Block<void*>& dataPtrs,
368 const Block<Int>& dataTypes, rownr_t index);
369
370 // Fill the row numbers vector for the given start till end in the
371 // <src>itsUniqueIndex</src> vector (end is not inclusive).
373
374 private:
375 // Fill the internal key fields from the corresponding external key.
376 void copyKey(Block<void*> fields, const Record& key);
377
378 // Fill the internal key field from the corresponding external key.
379 // The data type may differ.
380 template <typename T>
381 static void copyKeyField(RecordFieldPtr<T>& field, const Record& key) {
382 key.get(field.name(), *field);
383 }
384
391 Block<void*> itsData; // # pointer to data in itsDataVectors
392 // # The following 2 blocks are actually blocks of RecordFieldPtr<T>*.
393 // # They are used for fast access to the records.
398 Bool itsNoSort; // # True = sort is not needed
399 Compare* itsCompare; // # Compare function
400 Vector<rownr_t> itsDataIndex; // # Row numbers of all keys
401 // # Indices in itsDataIndex for each unique key
403 rownr_t* itsDataInx; // # pointer to data in itsDataIndex
404 rownr_t* itsUniqueInx; // # pointer to data in itsUniqueIndex
405};
406
408 return (itsDataIndex.nelements() == itsUniqueIndex.nelements());
409}
410inline const Table& ColumnsIndex::table() const { return itsTable; }
414
415} // namespace casacore
416
417#endif
const Table & table() const
Get the table for which this index is created.
RowNumbers getRowNumbers()
Find the row numbers matching the key.
RowNumbers getRowNumbers(const Record &key)
RowNumbers getRowNumbers(Bool lowerInclusive, Bool upperInclusive)
Find the row numbers matching the key range.
void copy(const ColumnsIndex &that)
Copy that object to this.
void fillRowNumbers(Vector< rownr_t > &rows, rownr_t start, rownr_t end) const
Fill the row numbers vector for the given start till end in the itsUniqueIndex vector (end is not inc...
void setChanged(const String &columnName)
ColumnsIndex(const Table &, const String &columnName, Compare *compareFunction=0, Bool noSort=False)
Create an index on the given table for the given column.
Vector< rownr_t > itsDataIndex
void setChanged()
Something has changed in the table, so the index has to be recreated.
Block< void * > itsUpperFields
Block< void * > itsDataVectors
void create(const Table &table, const Vector< String > &columnNames, Compare *compareFunction, Bool noSort)
Create the various members in the object.
void readData()
Read the data of the columns forming the index, sort them and form the index.
ColumnsIndex & operator=(const ColumnsIndex &that)
Assignment (copy semantics).
ColumnsIndex(const Table &, const Vector< String > &columnNames, Compare *compareFunction=0, Bool noSort=False)
Create an index on the given table for the given columns, thus the key is formed by multiple columns.
void addColumnToDesc(RecordDesc &description, const TableColumn &column)
Add a column to the record description for the keys.
ColumnsIndex(const ColumnsIndex &that)
Copy constructor (copy semantics).
Block< Bool > itsColumnChanged
rownr_t bsearch(Bool &found, const Block< void * > &fieldPtrs) const
Do a binary search on itsUniqueIndex for the key in fieldPtrs.
Block< void * > itsLowerFields
static void copyKeyField(void *field, int dtype, const Record &key)
Fill the internal key field from the corresponding external key.
Int Compare(const Block< void * > &fieldPtrs, const Block< void * > &dataPtrs, const Block< Int > &dataTypes, rownr_t index)
Define the signature of a comparison function.
Bool isUnique() const
Are all keys in the index unique?
void deleteObjects()
Delete all data in the object.
static Int compare(const Block< void * > &fieldPtrs, const Block< void * > &dataPtrs, const Block< Int > &dataTypes, rownr_t index)
Compare the key in fieldPtrs with the given index entry.
static void copyKeyField(RecordFieldPtr< T > &field, const Record &key)
Fill the internal key field from the corresponding external key.
Record & accessKey()
Access the key values.
Vector< String > columnNames() const
Return the names of the columns forming the index.
void copyKey(Block< void * > fields, const Record &key)
Fill the internal key fields from the corresponding external key.
Block< Int > itsDataTypes
Block< void * > itsData
Vector< rownr_t > itsUniqueIndex
rownr_t getRowNumber(Bool &found, const Record &key)
rownr_t getRowNumber(Bool &found)
Find the row number matching the key.
void makeObjects(const RecordDesc &description)
Make the various internal RecordFieldPtr objects.
RowNumbers getRowNumbers(const Record &lower, const Record &upper, Bool lowerInclusive, Bool upperInclusive)
String: the storage and methods of handling collections of characters.
Definition String.h:355
For temporary backward namespace compatibility, use casa as alias for casacore.
Definition mainpage.dox:28
const Bool False
Definition aipstype.h:42
const RecordDesc & description() const
Describes the current structure of this Record.
int Int
Definition aipstype.h:48
bool Bool
Define the standard types used by Casacore.
Definition aipstype.h:40
iterator end()
Definition Block.h:601
uInt64 rownr_t
Define the type of a row number in a table.
Definition aipsxtype.h:44