OpenTREP Logo  0.09.01
C++ Open Travel Request Parsing Library
Loading...
Searching...
No Matches
Result.cpp
Go to the documentation of this file.
1// //////////////////////////////////////////////////////////////////////
2// Import section
3// //////////////////////////////////////////////////////////////////////
4// STL
5#include <cassert>
6#include <sstream>
7#include <algorithm>
8// Boost
9#include <boost/tokenizer.hpp>
10// OpenTREP
21
22namespace OPENTREP {
23
24 // //////////////////////////////////////////////////////////////////////
25 Result::Result (const TravelQuery_T& iQueryString,
26 const Xapian::Database& iDatabase)
27 : _resultHolder (NULL), _database (iDatabase),
28 _queryString (iQueryString), _hasFullTextMatched (false),
29 _bestDocData (RawDataString_T ("")) {
30 init();
31 }
32
33 // //////////////////////////////////////////////////////////////////////
34 Result::~Result() {
35 }
36
37 // //////////////////////////////////////////////////////////////////////
38 void Result::init() {
39 }
40
41 // //////////////////////////////////////////////////////////////////////
42 std::string Result::describeShortKey() const {
43 std::ostringstream oStr;
44 oStr << _queryString;
45 return oStr.str();
46 }
47
48 // //////////////////////////////////////////////////////////////////////
49 std::string Result::describeKey() const {
50 std::ostringstream oStr;
51 oStr << "'" << describeShortKey() << "' ";
52 if (_correctedQueryString.empty() == false
53 && _correctedQueryString != _queryString) {
54 oStr << "(corrected into '" << _correctedQueryString
55 << "' with an edit distance/error of " << _editDistance
56 << " over an allowable distance of " << _allowableEditDistance
57 << ") - ";
58 } else {
59 oStr << "- ";
60 }
61 return oStr.str();
62 }
63
64 // //////////////////////////////////////////////////////////////////////
65 std::string Result::toString() const {
66 std::ostringstream oStr;
67 oStr << describeKey();
68
69 if (_documentList.empty() == true) {
70 oStr << "No match" << std::endl;
71 return oStr.str();
72 }
73 assert (_hasFullTextMatched == true);
74
75 unsigned short idx = 0;
76 for (DocumentList_T::const_iterator itDoc = _documentList.begin();
77 itDoc != _documentList.end(); ++itDoc, ++idx) {
78 const XapianDocumentPair_T& lDocumentPair = *itDoc;
79
80 const Xapian::Document& lXapianDoc = lDocumentPair.first;
81 const Xapian::docid& lDocID = lXapianDoc.get_docid();
82
83 const ScoreBoard& lScoreBoard = lDocumentPair.second;
84
85 if (idx != 0) {
86 oStr << ", ";
87 }
88 oStr << "Doc ID: " << lDocID << ", matching with ("
89 << lScoreBoard.describe() << "), containing: '"
90 << lXapianDoc.get_data() << "'";
91 }
92
93 return oStr.str();
94 }
95
96 // //////////////////////////////////////////////////////////////////////
97 void Result::toStream (std::ostream& ioOut) const {
98 ioOut << toString();
99 }
100
101 // //////////////////////////////////////////////////////////////////////
102 void Result::fromStream (std::istream& ioIn) {
103 }
104
105 // //////////////////////////////////////////////////////////////////////
106 const XapianDocumentPair_T& Result::
107 getDocumentPair (const Xapian::docid& iDocID) const {
108 // Retrieve the Xapian document and associated ScoreBoard structure
109 // corresponding to the doc ID of the best matching document
110 DocumentMap_T::const_iterator itDoc = _documentMap.find (iDocID);
111
112 if (itDoc == _documentMap.end()) {
113 OPENTREP_LOG_ERROR ("The Xapian document (ID = " << iDocID
114 << ") can not be found in the Result object "
115 << describeKey());
116 }
117 assert (itDoc != _documentMap.end());
118
119 //
120 const XapianDocumentPair_T& oDocumentPair = itDoc->second;
121
122 //
123 return oDocumentPair;
124 }
125
126 // //////////////////////////////////////////////////////////////////////
127 const Xapian::Document& Result::
128 getDocument (const Xapian::docid& iDocID) const {
129 // First, retrieve the pair made of Xapian document and associated
130 // ScoreBoard structure
131 const XapianDocumentPair_T& lDocumentPair = getDocumentPair (iDocID);
132
133 // Then, take the Xapian document (and leave the ScoreBoard out)
134 const Xapian::Document& oXapianDocument = lDocumentPair.first;
135
136 //
137 return oXapianDocument;
138 }
139
140 // //////////////////////////////////////////////////////////////////////
141 void Result::addDocument (const Xapian::Document& iDocument,
142 const Score_T& iScore) {
151 Score_T lCorrectedScore = iScore;
152 if (_editDistance > 0) {
153 lCorrectedScore = iScore / (_editDistance * _editDistance * _editDistance);
154 }
155
156 // The document is created at the time of (Xapian-based) full-text matching
157 const ScoreType lXapianScoreType (ScoreType::XAPIAN_PCT);
158
159 // Create a ScoreBoard structure
160 const ScoreBoard lScoreBoard (_queryString,
161 lXapianScoreType, lCorrectedScore);
162
163 // Retrieve the ID of the Xapian document
164 const Xapian::docid& lDocID = iDocument.get_docid();
165
174
175 // Create a (Xapian document, score board) pair, so as to store
176 // the document along with its corresponding score board
177 const XapianDocumentPair_T lDocumentPair (iDocument, lScoreBoard);
178
179 // Insert the just created pair into the dedicated (STL) list
180 _documentList.push_back (lDocumentPair);
181
182 // Insert the just created pair into the dedicated (STL) map
183 const bool hasInsertBeenSuccessful =
184 _documentMap.insert (DocumentMap_T::value_type (lDocID,
185 lDocumentPair)).second;
186 // Sanity check
187 if (hasInsertBeenSuccessful == false) {
188 std::ostringstream errorStr;
189 errorStr << "Error while inserting the Xapian Document pair into "
190 << "the internal STL map";
191 OPENTREP_LOG_DEBUG (errorStr.str());
192 }
193 assert (hasInsertBeenSuccessful == true);
194 }
195
196 // //////////////////////////////////////////////////////////////////////
197 void Result::fillResult (const Xapian::MSet& iMatchingSet) {
202 for (Xapian::MSetIterator itDoc = iMatchingSet.begin();
203 itDoc != iMatchingSet.end(); ++itDoc) {
204 const int& lXapianPercentage = itDoc.get_percent();
205 const Xapian::Document& lDocument = itDoc.get_document();
206 addDocument (lDocument, lXapianPercentage);
207 }
208 }
209
210 // //////////////////////////////////////////////////////////////////////
211 void Result::fillPlace (Place& ioPlace) const {
212 // Set the original and corrected/suggested keywords
213 ioPlace.setOriginalKeywords (_queryString);
214 ioPlace.setCorrectedKeywords (_correctedQueryString);
215
216 // Set the effective (Levenshtein) edit distance/error, as
217 // well as the allowable edit distance/error
218 ioPlace.setEditDistance (_editDistance);
219 ioPlace.setAllowableEditDistance (_allowableEditDistance);
220
221 // Set the Xapian document ID
222 ioPlace.setDocID (_bestDocID);
223
224 // Set the matching percentage
225 ioPlace.setPercentage (_bestCombinedWeight);
226
227 // Retrieve the parameters of the best matching document
228 const LocationKey& lKey = ioPlace.getKey();
229
230 // DEBUG
231 OPENTREP_LOG_DEBUG ("Place key: " << lKey << " - Xapian ID " << _bestDocID
232 << ", " << _bestCombinedWeight << "% [" << _bestDocData
233 << "]");
234 }
235
247 // //////////////////////////////////////////////////////////////////////
248 static unsigned int calculateEditDistance (const TravelQuery_T& iPhrase) {
249 NbOfErrors_T oEditDistance = 2;
250
251 const NbOfErrors_T lQueryStringSize = iPhrase.size();
252
253 oEditDistance = lQueryStringSize / K_DEFAULT_SIZE_FOR_SPELLING_ERROR_UNIT;
254 return oEditDistance;
255 }
256
257 // //////////////////////////////////////////////////////////////////////
259 // Initialise the POR (point of reference) parser
260 PORStringParser lStringParser (iRawDataString);
261
262 // Parse the raw data
263 const Location& oLocation = lStringParser.generateLocation();
264
265 // DEBUG
266 //OPENTREP_LOG_DEBUG ("Location: " << oLocation);
267
268 return oLocation;
269 }
270
271 // //////////////////////////////////////////////////////////////////////
272 Location Result::retrieveLocation (const Xapian::Document& iDocument) {
273 // Retrieve the Xapian document data
274 const std::string& lDocumentDataStr = iDocument.get_data();
275 const RawDataString_T& lDocumentData = RawDataString_T (lDocumentDataStr);
276
277 // Parse the POR details and create the corresponding Location structure
278 const Location& oLocation = retrieveLocation (lDocumentData);
279
280 return oLocation;
281 }
282
283 // //////////////////////////////////////////////////////////////////////
284 LocationKey Result::getPrimaryKey (const Xapian::Document& iDocument) {
285 // Parse the POR (point of reference) details held by the Xapian document
286 const Location& lLocation = retrieveLocation (iDocument);
287
288 // Get the key (IATA and ICAO codes, GeonamesID)
289 const LocationKey& oLocationKey = lLocation.getKey();
290
291 return oLocationKey;
292 }
293
294 // //////////////////////////////////////////////////////////////////////
295 Score_T Result::getEnvelopeID (const Xapian::Document& iDocument) {
296 // Parse the POR (point of reference) details held by the Xapian document
297 const Location& lLocation = retrieveLocation (iDocument);
298
299 // Get the envelope ID (it is an integer value in the Location structure)
300 const EnvelopeID_T& lEnvelopeIDInt = lLocation.getEnvelopeID();
301
302 // Convert the envelope ID value, from an integer to a floating point one
303 const Score_T oEnvelopeID = static_cast<const Score_T> (lEnvelopeIDInt);
304
305 return oEnvelopeID;
306 }
307
308 // //////////////////////////////////////////////////////////////////////
309 PageRank_T Result::getPageRank (const Xapian::Document& iDocument) {
310 // Parse the POR (point of reference) details held by the Xapian document
311 const Location& lLocation = retrieveLocation (iDocument);
312
313 // Get the PageRank value
314 const PageRank_T& oPageRank = lLocation.getPageRank();
315
316 return oPageRank;
317 }
318
319 // //////////////////////////////////////////////////////////////////////
320 std::string Result::fullTextMatch (const Xapian::Database& iDatabase,
321 const TravelQuery_T& iQueryString,
322 Xapian::MSet& ioMatchingSet,
323 const std::string& iNegativeQuery) {
324 std::string oMatchedString;
325
326 // Catch any Xapian::Error exceptions thrown
327 try {
328
329 // Build the query object
330 Xapian::QueryParser lQueryParser;
331 lQueryParser.set_database (iDatabase);
332
338 // lQueryParser.set_default_op (Xapian::Query::OP_ADJ);
339 lQueryParser.set_default_op (Xapian::Query::OP_PHRASE);
340
341 // DEBUG
342 /*
343 OPENTREP_LOG_DEBUG ("Query parser `" << lQueryParser.get_description()
344 << "'");
345 */
346
347 // DEBUG
348 OPENTREP_LOG_DEBUG (" --------");
349
350 // Start an enquire session
351 Xapian::Enquire enquire (iDatabase);
352 enquire.set_weighting_scheme(Xapian::BM25Weight(1.0, 0.0, 1.0, 0.0, 0.5));
353
360 std::string lQueryStringToParse = iQueryString;
361 if (!iNegativeQuery.empty()) {
362 lQueryStringToParse += " " + iNegativeQuery;
363 }
364
365 const Xapian::Query& lXapianQuery =
366 lQueryParser.parse_query (lQueryStringToParse,
367 Xapian::QueryParser::FLAG_BOOLEAN
368 | Xapian::QueryParser::FLAG_PHRASE
369 | Xapian::QueryParser::FLAG_LOVEHATE);
370
371 // Give the query object to the enquire session
372 enquire.set_query (lXapianQuery);
373
374 // Get the top K_DEFAULT_XAPIAN_MATCHING_SET_SIZE (normally, 30)
375 // results of the query
376 ioMatchingSet = enquire.get_mset (0, K_DEFAULT_XAPIAN_MATCHING_SET_SIZE);
377
378 // Display the results
379 int nbMatches = ioMatchingSet.size();
380
381 // DEBUG
382 OPENTREP_LOG_DEBUG (" Query string: `" << iQueryString
383 << "', i.e.: `" << lXapianQuery.get_description()
384 << "' => " << nbMatches << " result(s) found");
385
386 if (nbMatches != 0) {
387 // Store the effective (Levenshtein) edit distance/error
388 const NbOfErrors_T lEditDistance = 0;
389 setEditDistance (lEditDistance);
390
391 // Store the allowable edit distance/error
392 setAllowableEditDistance (lEditDistance);
393
394 //
395 oMatchedString = iQueryString;
396
397 // Store the fact that there has been a full-text match
398 setHasFullTextMatched (true);
399
400 // Store the corrected string (the same as the given string, here,
401 // as that latter directly gave full-text matches).
402 setCorrectedQueryString (oMatchedString);
403
404 // DEBUG
405 OPENTREP_LOG_DEBUG (" Query string: `" << iQueryString
406 << "' provides " << nbMatches << " exact matches.");
407
408 return oMatchedString;
409 }
410 assert (ioMatchingSet.empty() == true);
411
417 const NbOfErrors_T& lAllowableEditDistance =
418 calculateEditDistance (iQueryString);
419
420 // Let Xapian find a spelling correction (if any)
421 const std::string& lCorrectedString =
422 iDatabase.get_spelling_suggestion (iQueryString, lAllowableEditDistance);
423
424 // If the correction is no better than the original string, there is
425 // no need to go further: there is no match.
426 if (lCorrectedString.empty() == true || lCorrectedString == iQueryString) {
427 // DEBUG
428 OPENTREP_LOG_DEBUG (" Query string: `"
429 << iQueryString << "' provides no match, "
430 << "and there is no spelling suggestion, "
431 << "even with an edit distance of "
432 << lAllowableEditDistance);
433
434 // Store the fact that there has not been any full-text match
435 setHasFullTextMatched (false);
436
437 // Leave the string empty
438 return oMatchedString;
439 }
440 assert (lCorrectedString.empty() == false
441 && lCorrectedString != iQueryString);
442
443 // Calculate the effective (Levenshtein) edit distance/error
444 const NbOfErrors_T& lEditDistance =
445 Levenshtein::getDistance (iQueryString, lCorrectedString);
446
454 std::string lCorrectedQueryStringToParse = lCorrectedString;
455 if (!iNegativeQuery.empty()) {
456 lCorrectedQueryStringToParse += " " + iNegativeQuery;
457 }
458
459 const Xapian::Query& lCorrectedXapianQuery =
460 lQueryParser.parse_query (lCorrectedQueryStringToParse,
461 Xapian::QueryParser::FLAG_BOOLEAN
462 | Xapian::QueryParser::FLAG_PHRASE
463 | Xapian::QueryParser::FLAG_LOVEHATE);
464
465 // Retrieve a maximum of K_DEFAULT_XAPIAN_MATCHING_SET_SIZE (normally,
466 // 30) entries
467 enquire.set_query (lCorrectedXapianQuery);
468 ioMatchingSet = enquire.get_mset (0, K_DEFAULT_XAPIAN_MATCHING_SET_SIZE);
469
470 // Display the results
471 nbMatches = ioMatchingSet.size();
472
473 // DEBUG
474 OPENTREP_LOG_DEBUG (" Corrected query string: `" << lCorrectedString
475 << "', i.e.: `"
476 << lCorrectedXapianQuery.get_description()
477 << "' => " << nbMatches << " result(s) found");
478
479 if (nbMatches != 0) {
480 // Store the effective (Levenshtein) edit distance/error
481 setEditDistance (lEditDistance);
482
483 // Store the allowable edit distance/error
484 setAllowableEditDistance (lAllowableEditDistance);
485
486 //
487 oMatchedString = lCorrectedString;
488
489 // Store the fact that there has been a full-text match
490 setHasFullTextMatched (true);
491
492 // Store the corrected string
493 setCorrectedQueryString (oMatchedString);
494
495 // DEBUG
496 OPENTREP_LOG_DEBUG (" Query string: `"
497 << iQueryString << "', spelling suggestion: `"
498 << lCorrectedString
499 << "', with a Levenshtein edit distance of "
500 << lEditDistance
501 << " over an allowable edit distance of "
502 << lAllowableEditDistance << ", provides "
503 << nbMatches << " matches.");
504
505 //
506 return oMatchedString;
507 }
508
509 // Error
510 OPENTREP_LOG_ERROR (" Query string: `"
511 << iQueryString << "', spelling suggestion: `"
512 << lCorrectedString
513 << "', with a Levenshtein edit distance of "
514 << lEditDistance
515 << " over an allowable edit distance of "
516 << lAllowableEditDistance << ", provides no match, "
517 << "which is not consistent with the existence of "
518 << "the spelling correction.");
519 assert (false);
520
521 } catch (const Xapian::Error& error) {
522 OPENTREP_LOG_ERROR ("Exception: " << error.get_msg());
523 throw XapianException (error.get_msg());
524 }
525
526 // Store the fact that there has not been any full-text match
527 setHasFullTextMatched (false);
528
529 return oMatchedString;
530 }
531
532 // //////////////////////////////////////////////////////////////////////
533 std::string Result::fullTextMatch (const Xapian::Database& iDatabase,
534 const TravelQuery_T& iQueryString,
535 const std::string& iNegativeQuery) {
536 std::string oMatchedString;
537
538 // Catch any Xapian::Error exceptions thrown
539 try {
540
541 // DEBUG
542 OPENTREP_LOG_DEBUG (" ----------------");
543 OPENTREP_LOG_DEBUG (" Current query string: '"<< iQueryString << "'");
544
545 // Check whether the string should be filtered out
546 const bool isToBeAdded = Filter::shouldKeep ("", iQueryString);
547 //const bool isToBeAdded = true;
548
549 Xapian::MSet lMatchingSet;
550 if (isToBeAdded == true) {
551 oMatchedString = fullTextMatch (iDatabase, iQueryString, lMatchingSet, iNegativeQuery);
552 }
553
554 // Create the corresponding documents (from the Xapian MSet object)
555 fillResult (lMatchingSet);
556
557 // DEBUG
558 if (isToBeAdded == false) {
559 OPENTREP_LOG_DEBUG (" No full text search performed as '"
560 << iQueryString
561 << "' is not made of searchable words");
562 }
563 OPENTREP_LOG_DEBUG (" ==> " << toString());
564 OPENTREP_LOG_DEBUG (" ----------------");
565
566 } catch (const Xapian::Error& error) {
567 OPENTREP_LOG_ERROR ("Xapian-related error: " << error.get_msg());
568 throw XapianException (error.get_msg());
569 }
570
571 return oMatchedString;
572 }
573
574 // //////////////////////////////////////////////////////////////////////
576 // Browse the list of Xapian documents
577 for (DocumentList_T::const_iterator itDoc = _documentList.begin();
578 itDoc != _documentList.end(); ++itDoc) {
579 const XapianDocumentPair_T& lDocumentPair = *itDoc;
580
581 // Retrieve the Xapian document
582 const Xapian::Document& lXapianDoc = lDocumentPair.first;
583
584 // Extract the Xapian document ID
585 const Xapian::docid& lDocID = lXapianDoc.get_docid();
586
587 // Extract the envelope ID from the document data
588 const LocationKey& lLocationKey = getPrimaryKey (lXapianDoc);
589
590 // Retrieve the score board for that Xapian document
591 const ScoreBoard& lScoreBoard = lDocumentPair.second;
592
593 // Extract the Xapian matching percentage
594 const Score_T& lXapianPct = lScoreBoard.getScore (ScoreType::XAPIAN_PCT);
595
596 // DEBUG
598 << "' with (" << lLocationKey << ", doc ID = "
599 << lDocID << ") matches at " << lXapianPct
600 << "%");
601 }
602 }
603
604 // //////////////////////////////////////////////////////////////////////
605 void Result::setScoreOnDocMap (const Xapian::docid& iDocID,
606 const ScoreType& iType, const Score_T& iScore) {
607 // Retrieve the Xapian document and associated ScoreBoard structure
608 // corresponding to the given doc ID
609 DocumentMap_T::iterator itDoc = _documentMap.find (iDocID);
610
611 if (itDoc == _documentMap.end()) {
612 OPENTREP_LOG_ERROR ("The Xapian document (ID = " << iDocID
613 << ") can not be found in the Result object "
614 << describeKey());
615 }
616 assert (itDoc != _documentMap.end());
617
618 // Retrieve the associated ScoreBoard structure
619 XapianDocumentPair_T& lXapianDocPair = itDoc->second;
620 ScoreBoard& lScoreBoard = lXapianDocPair.second;
621
622 // Update the score/weight
623 lScoreBoard.setScore (iType, iScore);
624 }
625
626 // //////////////////////////////////////////////////////////////////////
628 // Browse the list of Xapian documents
629 for (DocumentList_T::iterator itDoc = _documentList.begin();
630 itDoc != _documentList.end(); ++itDoc) {
631 XapianDocumentPair_T& lDocumentPair = *itDoc;
632
633 // Retrieve the Xapian document
634 const Xapian::Document& lXapianDoc = lDocumentPair.first;
635
636 // Extract the Xapian document ID
637 const Xapian::docid& lDocID = lXapianDoc.get_docid();
638
639 // Extract the envelope ID from the document data
640 const LocationKey& lLocationKey = getPrimaryKey (lXapianDoc);
641
642 // Extract the envelope ID from the document data
643 const EnvelopeID_T& lEnvelopeIDInt = getEnvelopeID (lXapianDoc);
644
645 // DEBUG
646 if (lEnvelopeIDInt != 0) {
648 << "] (" << lLocationKey << ", doc ID = "
649 << lDocID << ") has a non-null envelope ID ("
650 << lEnvelopeIDInt << ") => match of 0.10%");
651 }
652
653 // Convert the envelope ID value, from an integer to a floating point one
654 const Score_T lEnvelopeID = static_cast<const Score_T> (lEnvelopeIDInt);
655
656 // Retrieve the score board for that Xapian document
657 ScoreBoard& lScoreBoard = lDocumentPair.second;
658
659 // Store the envelope-related weight
660 lScoreBoard.setScore (ScoreType::ENV_ID, lEnvelopeID);
661 setScoreOnDocMap (lDocID, ScoreType::ENV_ID, lEnvelopeID);
662 }
663 }
664
665 // //////////////////////////////////////////////////////////////////////
667 // Browse the list of Xapian documents
668 for (DocumentList_T::iterator itDoc = _documentList.begin();
669 itDoc != _documentList.end(); ++itDoc) {
670 XapianDocumentPair_T& lDocumentPair = *itDoc;
671
672 // Retrieve the Xapian document
673 const Xapian::Document& lXapianDoc = lDocumentPair.first;
674
675 // Extract the Xapian document ID
676 const Xapian::docid& lDocID = lXapianDoc.get_docid();
677
678 // Extract the envelope ID from the document data
679 const LocationKey& lLocationKey = getPrimaryKey (lXapianDoc);
680
681 // Initialisation of the IATA/ICAO code full matching percentage
682 Score_T lCodeMatchPct = 0.0;
683 bool hasCodeFullyMatched = false;
684
685 // Filter out "standard" words such as "airport", "international",
686 // "city", as well as words having a length strictly less than
687 // 3 letters.
688 std::string lFilteredString (_queryString);
689 const NbOfLetters_T kMinWordLength = 3;
690 Filter::trim (lFilteredString, kMinWordLength);
691
692 // Check whether or not the filtered query string is made of
693 // a single word
694 WordList_T lFilteredQueryWordList;
696 lFilteredQueryWordList);
697 const NbOfWords_T nbOfFilteredQueryWords = lFilteredQueryWordList.size();
698
699 //
700 if (_hasFullTextMatched == true) {
707 const size_t lNbOfLetters = lFilteredString.size();
708 if (nbOfFilteredQueryWords == 1
709 && lNbOfLetters >= 3 && lNbOfLetters <= 4
710 && _correctedQueryString == _queryString) {
711 // Convert the query string (made of one word of 3 or 4 letters)
712 // to uppercase letters
713 std::string lUpperQueryWord;
714 lUpperQueryWord.resize (lNbOfLetters);
715 std::transform (lFilteredString.begin(), lFilteredString.end(),
716 lUpperQueryWord.begin(), ::toupper);
717
718 // Retrieve with the IATA code
719 const IATACode_T& lIataCode = lLocationKey.getIataCode();
720
721 // Compare the 3/4-letter-word query string with the IATA
722 // and ICAO codes
723 if (lUpperQueryWord == lIataCode) {
727 lCodeMatchPct = 1.0;
728 hasCodeFullyMatched = true;
729 }
730 }
731
732 if (hasCodeFullyMatched == true) {
733 // DEBUG
735 << "' matches the IATA/ICAO code ("
736 << lLocationKey << ", doc ID = "
737 << lDocID << ") => match of "
739 } else {
740 // DEBUG
742 << "' does not match with the IATA/ICAO "
743 << "code (" << lLocationKey << ", doc ID = "
744 << lDocID << ") => match of "
746 }
747 }
748
749 // Retrieve the score board for that Xapian document
750 ScoreBoard& lScoreBoard = lDocumentPair.second;
751
752 // Store the IATA/ICAO code match percentage/weight
753 lScoreBoard.setScore (ScoreType::CODE_FULL_MATCH, lCodeMatchPct);
754 setScoreOnDocMap (lDocID, ScoreType::CODE_FULL_MATCH, lCodeMatchPct);
755 }
756 }
757
758 // //////////////////////////////////////////////////////////////////////
760 // Browse the list of Xapian documents
761 for (DocumentList_T::iterator itDoc = _documentList.begin();
762 itDoc != _documentList.end(); ++itDoc) {
763 XapianDocumentPair_T& lDocumentPair = *itDoc;
764
765 // Retrieve the Xapian document
766 const Xapian::Document& lXapianDoc = lDocumentPair.first;
767
768 // Extract the Xapian document ID
769 const Xapian::docid& lDocID = lXapianDoc.get_docid();
770
771 // Extract the envelope ID from the document data
772 const LocationKey& lLocationKey = getPrimaryKey (lXapianDoc);
773
774 // Extract the PageRank from the document data
775 const Score_T& lPageRank = getPageRank (lXapianDoc);
776
777 // DEBUG
779 << "] (" << lLocationKey << ", doc ID = "
780 << lDocID << ") has a PageRank of "
781 << lPageRank << "%");
782
783 // Retrieve the score board for that Xapian document
784 ScoreBoard& lScoreBoard = lDocumentPair.second;
785
786 // Store the PageRank weight
787 lScoreBoard.setScore (ScoreType::PAGE_RANK, lPageRank);
788 setScoreOnDocMap (lDocID, ScoreType::PAGE_RANK, lPageRank);
789 }
790 }
791
792 // //////////////////////////////////////////////////////////////////////
800
801 // //////////////////////////////////////////////////////////////////////
803 Percentage_T lMaxPercentage = 0.0;
804 std::string lBestDocData;
805
806 // Browse the list of Xapian documents
807 Xapian::docid lBestDocID = 0;
808 for (DocumentList_T::iterator itDoc = _documentList.begin();
809 itDoc != _documentList.end(); ++itDoc) {
810 XapianDocumentPair_T& lDocumentPair = *itDoc;
811
812 // Retrieve the Xapian document ID
813 const Xapian::Document& lXapianDoc = lDocumentPair.first;
814 const Xapian::docid& lDocID = lXapianDoc.get_docid();
815 const std::string& lDocData = lXapianDoc.get_data();
816
821 ScoreBoard& lScoreBoard = lDocumentPair.second;
822 const Percentage_T& lPercentage = lScoreBoard.calculateCombinedWeight();
823
832
833 // Register the document, if it is the best matching until now
834 if (lPercentage > lMaxPercentage) {
835 lMaxPercentage = lPercentage;
836 lBestDocID = lDocID;
837 lBestDocData = lDocData;
838 }
839 }
840
841 // Check whether or not the (original) query string is made of a single word
842 WordList_T lOriginalQueryWordList;
844 lOriginalQueryWordList);
845 const NbOfWords_T nbOfOriginalQueryWords = lOriginalQueryWordList.size();
846
847 //
848 if (_hasFullTextMatched == true) {
849 // Retrieve the primary key (IATA, location type, Geonames ID) of
850 // the place corresponding to the document
851 const XapianDocumentPair_T& lXapianDocPair = getDocumentPair (lBestDocID);
852 const Xapian::Document& lXapianDoc = lXapianDocPair.first;
853 const ScoreBoard& lScoreBoard = lXapianDocPair.second;
854 const LocationKey& lLocationKey = getPrimaryKey (lXapianDoc);
855
856 // DEBUG
857 OPENTREP_LOG_DEBUG (" [pct] '" << describeShortKey()
858 << "' matches at " << lMaxPercentage
859 << "% for " << lLocationKey << " (doc ID = "
860 << lBestDocID << "). Score calculation: "
861 << lScoreBoard.describe());
862
863 } else {
868 const bool shouldBeKept = Filter::shouldKeep ("", _queryString);
869
870 if (nbOfOriginalQueryWords == 1 && shouldBeKept == true) {
876 lMaxPercentage = 100.0;
877
878 // DEBUG
879 OPENTREP_LOG_DEBUG (" [pct] '" << describeShortKey()
880 << "' does not match, but it is a non black-listed "
881 << "single-word string; hence, the weight is "
882 << lMaxPercentage << "%");
883
884 } else {
893 lMaxPercentage = std::pow (10.0, -3*nbOfOriginalQueryWords);
894
895 // DEBUG
897 << "' does not match, and is either a multiple-word "
898 << "string or black-listed; hence, the weight is "
899 << lMaxPercentage << "%");
900 }
901 }
902
903 // Store the doc ID of the best matching document
904 setBestDocID (lBestDocID);
905
906 // Store the best weight
907 setBestCombinedWeight (lMaxPercentage);
908
909 // Store all the details of the Xapian document
910 setBestDocData (lBestDocData);
911 }
912
913}
#define OPENTREP_LOG_ERROR(iToBeLogged)
Definition Logger.hpp:24
#define OPENTREP_LOG_DEBUG(iToBeLogged)
Definition Logger.hpp:33
#define OPENTREP_LOG_NOTIFICATION(iToBeLogged)
Definition Logger.hpp:27
const Location & generateLocation()
Class modelling a place/POR (point of reference).
Definition Place.hpp:29
void setEditDistance(const NbOfErrors_T &iEditDistance)
Definition Place.hpp:898
void setDocID(const XapianDocID_T &iDocID)
Definition Place.hpp:920
void setAllowableEditDistance(const NbOfErrors_T &iAllowableEditDistance)
Definition Place.hpp:906
void setPercentage(const MatchingPercentage_T &iPercentage)
Definition Place.hpp:891
void setOriginalKeywords(const std::string &iOriginalKeywords)
Definition Place.hpp:877
const LocationKey & getKey() const
Definition Place.hpp:59
void setCorrectedKeywords(const std::string &iCorrectedKeywords)
Definition Place.hpp:884
void setScoreOnDocMap(const Xapian::docid &, const ScoreType &, const Score_T &)
Definition Result.cpp:605
void addDocument(const Xapian::Document &, const Score_T &)
Definition Result.cpp:141
void setBestCombinedWeight(const Percentage_T &iPercentage)
Definition Result.hpp:215
void displayXapianPercentages() const
Definition Result.cpp:575
void fillResult(const Xapian::MSet &iMatchingSet)
Definition Result.cpp:197
const XapianDocumentPair_T & getDocumentPair(const Xapian::docid &) const
Definition Result.cpp:107
void setBestDocData(const std::string &iDocData)
Definition Result.hpp:222
void fillPlace(Place &) const
Definition Result.cpp:211
void toStream(std::ostream &ioOut) const
Definition Result.cpp:97
void calculatePageRanks()
Definition Result.cpp:759
void setBestDocID(const Xapian::docid &iDocID)
Definition Result.hpp:207
static Score_T getEnvelopeID(const Xapian::Document &)
Definition Result.cpp:295
static PageRank_T getPageRank(const Xapian::Document &)
Definition Result.cpp:309
std::string toString() const
Definition Result.cpp:65
void fromStream(std::istream &ioIn)
Definition Result.cpp:102
std::string describeShortKey() const
Definition Result.cpp:42
static Location retrieveLocation(const Xapian::Document &)
Definition Result.cpp:272
std::string fullTextMatch(const Xapian::Database &, const TravelQuery_T &, const std::string &="")
Definition Result.cpp:533
void calculateHeuristicWeights()
Definition Result.cpp:793
void calculateEnvelopeWeights()
Definition Result.cpp:627
void calculateCodeMatches()
Definition Result.cpp:666
static LocationKey getPrimaryKey(const Xapian::Document &)
Definition Result.cpp:284
void calculateCombinedWeights()
Definition Result.cpp:802
std::string describeKey() const
Definition Result.cpp:49
static void tokeniseStringIntoWordList(const TravelQuery_T &, WordList_T &)
std::list< Word_T > WordList_T
unsigned int NbOfLetters_T
unsigned short NbOfErrors_T
const Percentage_T K_DEFAULT_MODIFIED_MATCHING_PCT
std::string TravelQuery_T
double Percentage_T
static unsigned int calculateEditDistance(const TravelQuery_T &iPhrase)
Helper function.
double PageRank_T
unsigned int EnvelopeID_T
const Percentage_T K_DEFAULT_FULL_CODE_MATCH_PCT
std::pair< Xapian::Document, ScoreBoard > XapianDocumentPair_T
Definition Result.hpp:30
const NbOfErrors_T K_DEFAULT_SIZE_FOR_SPELLING_ERROR_UNIT
unsigned short NbOfWords_T
std::string toString(const TokenList_T &iTokenList)
static void trim(std::string &ioPhrase, const NbOfLetters_T &iMinWordLength=4)
Definition Filter.cpp:131
static bool shouldKeep(const std::string &iPhrase, const std::string &iWord)
Definition Filter.cpp:144
Class modelling the primary key of a location/POR (point of reference).
const IATACode_T & getIataCode() const
Structure modelling a (geographical) location.
Definition Location.hpp:25
const LocationKey & getKey() const
Definition Location.hpp:31
const EnvelopeID_T & getEnvelopeID() const
Definition Location.hpp:123
const PageRank_T & getPageRank() const
Definition Location.hpp:354
Structure holding a board for all the types of score/matching having been performed.
Percentage_T calculateCombinedWeight()
std::string describe() const
void setScore(const ScoreType &, const Score_T &)
Score_T getScore(const ScoreType &) const
Enumeration of score types.
Definition ScoreType.hpp:25