OpenTREP Logo  0.08.02
C++ Open Travel Request Parsing Library
Loading...
Searching...
No Matches
IndexBuilder.cpp
Go to the documentation of this file.
1// //////////////////////////////////////////////////////////////////////
2// Import section
3// //////////////////////////////////////////////////////////////////////
4// STL
5#include <cassert>
6#include <string>
7#include <vector>
8#include <exception>
9// Boost
10#include <boost/filesystem.hpp>
11#include <boost/filesystem/fstream.hpp>
12#include <boost/tokenizer.hpp>
13#include <boost/iostreams/device/file.hpp>
14#include <boost/iostreams/filtering_stream.hpp>
15#include <boost/iostreams/filter/gzip.hpp>
16#include <boost/iostreams/filter/bzip2.hpp>
17// SOCI
18#include <soci/soci.h>
19// Xapian
20#include <xapian.h>
21// OpenTrep
36
37namespace OPENTREP {
38
39 // //////////////////////////////////////////////////////////////////////
40 void addToXapian (const Place& iPlace, Xapian::Document& ioDocument,
41 Xapian::WritableDatabase& ioDatabase) {
48 Xapian::TermGenerator lTermGenerator;
49 lTermGenerator.set_database (ioDatabase);
50 lTermGenerator.set_document (ioDocument);
51
52 // DEBUG
53 // OPENTREP_LOG_DEBUG ("Indexing for " << iPlace.describeKey());
54
55 const Place::TermSetMap_T& lTermSetMap = iPlace.getTermSetMap();
56 for (Place::TermSetMap_T::const_iterator itStringSet = lTermSetMap.begin();
57 itStringSet != lTermSetMap.end(); ++itStringSet) {
58 // Retrieve the weight
59 const Weight_T& lWeight = itStringSet->first;
60 const Xapian::termcount lWDFInc =
61 static_cast<const Xapian::termcount> (lWeight);
62
63 // Retrieve the set of strings for that weight
64 const Place::StringSet_T& lTermSet = itStringSet->second;
65 for (Place::StringSet_T::const_iterator itString = lTermSet.begin();
66 itString != lTermSet.end(); ++itString) {
67 const std::string& lString = *itString;
68 lTermGenerator.index_text (lString, lWDFInc);
69
70 // DEBUG
71 //OPENTREP_LOG_DEBUG("[" << lWeight << "/" << lWDFInc << "] "<< lString);
72 }
73 }
74
75 // Spelling terms
76 const Place::StringSet_T& lSpellingSet = iPlace.getSpellingSet();
77 for (Place::StringSet_T::const_iterator itTerm = lSpellingSet.begin();
78 itTerm != lSpellingSet.end(); ++itTerm) {
79 const std::string& lTerm = *itTerm;
80 // Xapian prefixes spelling keys with 'W', while backend keys are
81 // limited to 255 bytes.
82 if (lTerm.size() <= 254) {
83 ioDatabase.add_spelling (lTerm);
84 }
85 }
86
87 // DEBUG
88 OPENTREP_LOG_DEBUG ("Added terms for '" << iPlace.describeKey()
89 << "': " << iPlace.describeSets()
90 << " into " << ioDocument.get_description());
91 }
92
93 // //////////////////////////////////////////////////////////////////////
94 void IndexBuilder::addDocumentToIndex(Xapian::WritableDatabase& ioDatabase,
95 Place& ioPlace,
96 const OTransliterator& iTransliterator) {
97
98 // Create an empty Xapian document
99 Xapian::Document lDocument;
100
101 // Retrieve the raw data string, to be stored as is within
102 // the Xapian document
103 const RawDataString_T& lRawDataString = ioPlace.getRawDataString();
104
105 // The Xapian document data is indeed the same as the one of the
106 // OPTD-maintained list of POR (points of reference), allowing the search
107 // process to use exactly the same parser as the indexation process
108 lDocument.set_data (lRawDataString);
109
110 // Build the (STL) sets of terms to be added to the Xapian index and
111 // spelling dictionary
112 ioPlace.buildIndexSets (iTransliterator);
113
114 // Add the (STL) sets of terms to the Xapian index and spelling dictionary
115 addToXapian (ioPlace, lDocument, ioDatabase);
116
117 // Add the document to the database
118 const Xapian::docid& lDocID = ioDatabase.add_document (lDocument);
119
120 // Assign back the newly generated Xapian document ID to the
121 // Place object
122 ioPlace.setDocID (lDocID);
123 }
124
125 // //////////////////////////////////////////////////////////////////////
126 NbOfDBEntries_T IndexBuilder::
127 buildSearchIndex (Xapian::WritableDatabase* ioXapianDB_ptr,
128 const DBType& iSQLDBType, soci::session* ioSociSessionPtr,
129 std::istream& iPORFileStream,
130 const shouldIndexNonIATAPOR_T& iIncludeNonIATAPOR,
131 const OTransliterator& iTransliterator) {
132 NbOfDBEntries_T oNbOfEntries = 0;
133 NbOfDBEntries_T oNbOfEntriesInPORFile = 0;
134
135 // Open the file to be parsed
136 Place& lPlace = FacPlace::instance().create();
137 std::string itReadLine;
138 while (std::getline (iPORFileStream, itReadLine)) {
139
140 /* First, if only the IATA-refernced POR must be indexed
141 * (ie, when iIncludeNonIATAPOR is set to false), the line
142 * must start with a non empty IATA code of three letters;
143 * in other words, the separator (the hat symbol) is first seen
144 * at position 3 (remember that strings in C++ start at position 0).
145 * Otherwise, the line is skipped.
146 */
147 if (!iIncludeNonIATAPOR) {
148 const unsigned short lFirstSeparatorPos = itReadLine.find_first_of ("^");
149 if (lFirstSeparatorPos != 3) {
150 // DEBUG
151 /*
152 OPENTREP_LOG_ERROR ("[" << oNbOfEntries << "] pos of sep: "
153 << lFirstSeparatorPos << ", full line: "
154 << itReadLine);
155 */
156
157 //
158 ++oNbOfEntriesInPORFile;
159
160 //
161 continue;
162 }
163 }
164
165 // Initialise the parser
166 PORStringParser lStringParser (itReadLine);
167
168 // Parse the string
169 const Location& lLocation = lStringParser.generateLocation();
170
171 // DEBUG
172 /*
173 const LocationKey& lLocationKey = lLocation.getKey();
174 OPENTREP_LOG_DEBUG ("[BEF-ADD] " << lLocationKey);
175 */
176
177 /* When the line/string is relevant, create a BOM instance from
178 * the Location structure.
179 * Otherwise, the line is skipped.
180 */
181 const std::string& lCommonName = lLocation.getCommonName();
182 if (lCommonName == "NotAvailable") {
183 continue;
184 }
185
186 // Fill the Place object with the Location structure.
187 lPlace.setLocation (lLocation);
188
189 // Add the document, associated to the Place object, to the Xapian index,
190 // if required
191 if (ioXapianDB_ptr != NULL) {
192 try {
193 IndexBuilder::addDocumentToIndex (*ioXapianDB_ptr, lPlace,
194 iTransliterator);
195 } catch (const Xapian::Error& iError) {
196 std::ostringstream errorStr;
197 errorStr << "Xapian failed while indexing '"
198 << lPlace.describeKey() << "': "
199 << iError.get_description();
200 OPENTREP_LOG_ERROR (errorStr.str());
201 throw XapianDatabaseFailureException (errorStr.str());
202 }
203 }
204
205 // Add the document to the SQL database, if required
206 if (ioSociSessionPtr != NULL) {
207 DBManager::insertPlaceInDB (*ioSociSessionPtr, lPlace);
208 }
209
210 // DEBUG
211 /*
212 OPENTREP_LOG_DEBUG ("[AFT-ADD] " << lLocationKey
213 << ", Place: " << lPlace);
214 */
215
216 // Iteration
217 ++oNbOfEntries; ++oNbOfEntriesInPORFile;
218
219 // Progress status
220 if (oNbOfEntries % 1000 == 0) {
221 std::cout.imbue( std::locale (std::locale::classic(), new NumSep));
222 std::cout << "Number of actually parsed records: " << oNbOfEntries
223 << ", out of " << oNbOfEntriesInPORFile
224 << " records in the POR data file so far" << std::endl;
225 }
226
227 // DEBUG
228 OPENTREP_LOG_DEBUG ("[" << oNbOfEntries << "] " << lPlace);
229
230 // Reset for next turn
231 lPlace.resetMatrix();
232 lPlace.resetIndexSets();
233 }
234
235 return oNbOfEntries;
236 }
237
238 // //////////////////////////////////////////////////////////////////////
239 NbOfDBEntries_T IndexBuilder::
240 buildSearchIndex (const PORFilePath_T& iPORFilePath,
241 const TravelDBFilePath_T& iTravelIndexFilePath,
242 const DBType& iSQLDBType,
243 const SQLDBConnectionString_T& iSQLDBConnStr,
244 const shouldIndexNonIATAPOR_T& iIncludeNonIATAPOR,
245 const shouldIndexPORInXapian_T& iShouldIndexPORInXapian,
246 const shouldAddPORInSQLDB_T& iShouldAddPORInSQLDB,
247 const OTransliterator& iTransliterator) {
248 NbOfDBEntries_T oNbOfEntries = 0;
249 soci::session* lSociSession_ptr = NULL;
250 Xapian::WritableDatabase* lXapianDatabase_ptr = NULL;
251
259 if (iShouldIndexPORInXapian) {
260 // Delete and recreate the directory, and its full content,
261 // hosting the Xapian index / database
262 FileManager::recreateXapianDirectory (iTravelIndexFilePath);
263
264 // Recreate the Xapian index / database
265 lXapianDatabase_ptr =
266 FacXapianDB::instance().create (iTravelIndexFilePath, Xapian::DB_CREATE);
267 assert (lXapianDatabase_ptr != NULL);
268
269 // DEBUG
270 OPENTREP_LOG_DEBUG ("The Xapian index / database ('"
271 << iTravelIndexFilePath
272 << "') has been re-created, checked and opened");
273
274
275 }
276
282 if (iShouldAddPORInSQLDB) {
283 /*
284 // Creation of the trep user and trep_trep database
285 bool isSuccessful = DBManager::createSQLDBUser (iSQLDBType, iSQLDBConnStr);
286 if (isSuccessful == false) {
287 std::ostringstream errorStr;
288 errorStr << "Error when trying to re-initialize the SQL database ('"
289 << iSQLDBConnStr << "')";
290 OPENTREP_LOG_ERROR (errorStr.str());
291 throw SQLDatabaseImpossibleConnectionException (errorStr.str());
292 }
293 */
294
298 if (!(iSQLDBType == DBType::NODB)) {
299 // Connection to the database
300 lSociSession_ptr =
301 DBManager::initSQLDBSession (iSQLDBType, iSQLDBConnStr);
302
303 if (lSociSession_ptr == NULL) {
304 std::ostringstream errorStr;
305 errorStr << "Error when trying to connect to the SQL database ('"
306 << iSQLDBConnStr << "')";
307 OPENTREP_LOG_ERROR (errorStr.str());
308 throw SQLDatabaseImpossibleConnectionException (errorStr.str());
309 }
310 assert (lSociSession_ptr != NULL);
311
312 // Creation of the POR table
313 DBManager::createSQLDBTables (*lSociSession_ptr);
314 }
315 }
316
320 // DEBUG
321 OPENTREP_LOG_DEBUG ("Parsing POR input file: " << iPORFilePath);
322
323 // Get a reference on the file stream corresponding to the POR file.
324 const PORFileHelper lPORFileHelper (iPORFilePath);
325 std::istream& lPORFileStream = lPORFileHelper.getFileStreamRef();
326
327 // Browse the input POR (point of reference) data file,
328 // parse every of its rows, and put the result in the Xapian database/index
329 // and, if needed, within the SQL database.
330 oNbOfEntries = buildSearchIndex (lXapianDatabase_ptr, iSQLDBType,
331 lSociSession_ptr, lPORFileStream,
332 iIncludeNonIATAPOR, iTransliterator);
333
338 if (iShouldIndexPORInXapian) {
339 assert (lXapianDatabase_ptr != NULL);
340 // Xapian automatically commits batches as its flush threshold is
341 // reached. A single atomic transaction for a production POR file can
342 // grow too large for the backend to commit.
343 lXapianDatabase_ptr->commit();
344
345 // DEBUG
346 OPENTREP_LOG_DEBUG ("Xapian has indexed " << oNbOfEntries << " entries.");
347 }
348
356 if (iShouldIndexPORInXapian) {
357 assert (lXapianDatabase_ptr != NULL);
358 lXapianDatabase_ptr->close();
359 }
360
361
362 if (iShouldAddPORInSQLDB) {
366 if (!(iSQLDBType == DBType::NODB)) {
367 assert (lSociSession_ptr != NULL);
368 DBManager::createSQLDBIndexes (*lSociSession_ptr);
369 }
370
374 if (!(iSQLDBType == DBType::NODB)) {
375 assert (lSociSession_ptr != NULL);
376 DBManager::terminateSQLDBSession (iSQLDBType, iSQLDBConnStr,
377 *lSociSession_ptr);
378 }
379 }
380
381 return oNbOfEntries;
382 }
383
384}
#define OPENTREP_LOG_ERROR(iToBeLogged)
Definition Logger.hpp:24
#define OPENTREP_LOG_DEBUG(iToBeLogged)
Definition Logger.hpp:33
static void terminateSQLDBSession(const DBType &, const SQLDBConnectionString_T &, soci::session &)
static void createSQLDBTables(soci::session &)
static soci::session * initSQLDBSession(const DBType &, const SQLDBConnectionString_T &)
static void createSQLDBIndexes(soci::session &)
static void insertPlaceInDB(soci::session &, const Place &)
static FacPlace & instance()
Definition FacPlace.cpp:29
static FacXapianDB & instance()
Xapian::WritableDatabase * create(const TravelDBFilePath_T &, const int &iXapianActionFlag)
static void recreateXapianDirectory(const std::string &iTravelDBFilePath)
Class modelling a place/POR (point of reference).
Definition Place.hpp:29
std::map< const Weight_T, StringSet_T > TermSetMap_T
Definition Place.hpp:41
std::string describeSets() const
Definition Place.cpp:157
const StringSet_T & getSpellingSet() const
Definition Place.hpp:509
std::set< std::string > StringSet_T
Definition Place.hpp:40
std::string describeKey() const
Definition Place.hpp:1053
const TermSetMap_T & getTermSetMap() const
Definition Place.hpp:495
void addToXapian(const Place &iPlace, Xapian::Document &ioDocument, Xapian::WritableDatabase &ioDatabase)
unsigned short Weight_T
bool shouldAddPORInSQLDB_T
unsigned int NbOfDBEntries_T
bool shouldIndexPORInXapian_T
bool shouldIndexNonIATAPOR_T
Enumeration of database types.
Definition DBType.hpp:17