2013-11-28 16:47:57 +01:00
|
|
|
#include "concordia/index_searcher.hpp"
|
|
|
|
|
2013-12-06 22:29:25 +01:00
|
|
|
#include "concordia/common/utils.hpp"
|
2015-06-26 22:50:53 +02:00
|
|
|
#include "concordia/tokenized_sentence.hpp"
|
2013-11-28 16:47:57 +01:00
|
|
|
#include <boost/filesystem.hpp>
|
2019-01-09 18:31:52 +01:00
|
|
|
#include <algorithm>
|
2013-11-28 16:47:57 +01:00
|
|
|
|
2013-12-14 15:23:17 +01:00
|
|
|
IndexSearcher::IndexSearcher() {
|
2015-04-24 11:48:32 +02:00
|
|
|
_concordiaSearcher = boost::shared_ptr<ConcordiaSearcher>(
|
|
|
|
new ConcordiaSearcher());
|
2013-11-28 16:47:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
IndexSearcher::~IndexSearcher() {
|
|
|
|
}
|
|
|
|
|
2017-04-21 14:51:58 +02:00
|
|
|
MatchedPatternFragment IndexSearcher::simpleSearch(
|
2014-02-20 10:49:17 +01:00
|
|
|
boost::shared_ptr<HashGenerator> hashGenerator,
|
|
|
|
boost::shared_ptr<std::vector<sauchar_t> > T,
|
|
|
|
boost::shared_ptr<std::vector<SUFFIX_MARKER_TYPE> > markers,
|
|
|
|
boost::shared_ptr<std::vector<saidx_t> > SA,
|
2017-04-22 23:45:51 +02:00
|
|
|
const std::string & pattern,
|
|
|
|
bool byWhitespace) throw(ConcordiaException) {
|
2013-11-28 16:47:57 +01:00
|
|
|
int left;
|
2015-04-15 14:14:10 +02:00
|
|
|
std::vector<INDEX_CHARACTER_TYPE> hash =
|
2017-04-22 23:47:48 +02:00
|
|
|
hashGenerator->generateHash(pattern, byWhitespace).getCodes();
|
2015-04-15 10:55:26 +02:00
|
|
|
saidx_t patternLength = hash.size()*sizeof(INDEX_CHARACTER_TYPE);
|
2013-12-06 22:29:25 +01:00
|
|
|
sauchar_t * patternArray = Utils::indexVectorToSaucharArray(hash);
|
2014-05-15 22:20:31 +02:00
|
|
|
|
2013-12-14 15:23:17 +01:00
|
|
|
int size = sa_search(T->data(), (saidx_t) T->size(),
|
|
|
|
(const sauchar_t *) patternArray, patternLength,
|
2014-05-14 16:29:44 +02:00
|
|
|
SA->data(), (saidx_t) SA->size(), &left);
|
2017-04-21 14:51:58 +02:00
|
|
|
MatchedPatternFragment result(0, hash.size());
|
2013-12-06 22:29:25 +01:00
|
|
|
for (int i = 0; i < size; ++i) {
|
2014-02-20 10:49:17 +01:00
|
|
|
saidx_t resultPos = SA->at(left + i);
|
|
|
|
if (resultPos % sizeof(INDEX_CHARACTER_TYPE) == 0) {
|
2013-12-06 22:29:25 +01:00
|
|
|
// As we are looking for a pattern in an array of higher
|
|
|
|
// resolution than the hashed index file, we might
|
|
|
|
// obtain accidental results exceeding the boundaries
|
|
|
|
// of characters in hashed index. The above check
|
|
|
|
// removes these accidental results.
|
2014-02-20 10:49:17 +01:00
|
|
|
saidx_t actualResultPos = resultPos / sizeof(INDEX_CHARACTER_TYPE);
|
|
|
|
SUFFIX_MARKER_TYPE marker = markers->at(actualResultPos);
|
2017-04-21 14:51:58 +02:00
|
|
|
|
|
|
|
SubstringOccurence occurence;
|
|
|
|
occurence.enterDataFromMarker(marker);
|
|
|
|
result.addOccurence(occurence);
|
|
|
|
if (result.getOccurences().size() >= CONCORDIA_SEARCH_MAX_RESULTS) {
|
2016-01-25 22:42:42 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-12-06 22:29:25 +01:00
|
|
|
}
|
2013-11-28 16:47:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
delete[] patternArray;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-01-09 15:30:56 +01:00
|
|
|
OccurencesList IndexSearcher::fullSearch(
|
|
|
|
boost::shared_ptr<HashGenerator> hashGenerator,
|
|
|
|
boost::shared_ptr<std::vector<sauchar_t> > T,
|
|
|
|
boost::shared_ptr<std::vector<SUFFIX_MARKER_TYPE> > markers,
|
|
|
|
boost::shared_ptr<std::vector<saidx_t> > SA,
|
|
|
|
const std::string & pattern,
|
2019-01-09 18:31:52 +01:00
|
|
|
int limit,
|
|
|
|
int offset,
|
2019-01-09 15:30:56 +01:00
|
|
|
bool byWhitespace) throw(ConcordiaException) {
|
|
|
|
int left;
|
|
|
|
std::vector<INDEX_CHARACTER_TYPE> hash =
|
|
|
|
hashGenerator->generateHash(pattern, byWhitespace).getCodes();
|
|
|
|
saidx_t patternLength = hash.size()*sizeof(INDEX_CHARACTER_TYPE);
|
|
|
|
sauchar_t * patternArray = Utils::indexVectorToSaucharArray(hash);
|
|
|
|
|
|
|
|
int size = sa_search(T->data(), (saidx_t) T->size(),
|
|
|
|
(const sauchar_t *) patternArray, patternLength,
|
|
|
|
SA->data(), (saidx_t) SA->size(), &left);
|
|
|
|
|
|
|
|
OccurencesList result(size);
|
2019-01-09 18:31:52 +01:00
|
|
|
|
|
|
|
int returnedResults = limit;
|
|
|
|
if ((size - offset) < limit) {
|
|
|
|
returnedResults = size - offset;
|
|
|
|
}
|
|
|
|
for (int i = 0; i < returnedResults; ++i) {
|
|
|
|
saidx_t resultPos = SA->at(left + offset + i);
|
2019-01-09 15:30:56 +01:00
|
|
|
if (resultPos % sizeof(INDEX_CHARACTER_TYPE) == 0) {
|
|
|
|
// As we are looking for a pattern in an array of higher
|
|
|
|
// resolution than the hashed index file, we might
|
|
|
|
// obtain accidental results exceeding the boundaries
|
|
|
|
// of characters in hashed index. The above check
|
|
|
|
// removes these accidental results.
|
|
|
|
saidx_t actualResultPos = resultPos / sizeof(INDEX_CHARACTER_TYPE);
|
|
|
|
SUFFIX_MARKER_TYPE marker = markers->at(actualResultPos);
|
|
|
|
|
|
|
|
SubstringOccurence occurence;
|
|
|
|
occurence.enterDataFromMarker(marker);
|
|
|
|
result.addOccurence(occurence);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] patternArray;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-10-10 15:39:47 +02:00
|
|
|
MatchedPatternFragment IndexSearcher::lexiconSearch(
|
|
|
|
boost::shared_ptr<HashGenerator> hashGenerator,
|
|
|
|
boost::shared_ptr<std::vector<sauchar_t> > T,
|
|
|
|
boost::shared_ptr<std::vector<SUFFIX_MARKER_TYPE> > markers,
|
|
|
|
boost::shared_ptr<std::vector<saidx_t> > SA,
|
|
|
|
const std::string & pattern,
|
|
|
|
bool byWhitespace) throw(ConcordiaException) {
|
|
|
|
int left;
|
|
|
|
std::vector<INDEX_CHARACTER_TYPE> hash =
|
|
|
|
hashGenerator->generateHash(pattern, byWhitespace).getCodes();
|
|
|
|
|
|
|
|
if (hash.size() == 0) {
|
|
|
|
// If the hash is empty, return empty result
|
|
|
|
return MatchedPatternFragment(0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// append and prepend query with EOS (sentenceBoundaryHI) for lexicon search
|
|
|
|
INDEX_CHARACTER_TYPE sentenceBoundaryHI = INDEX_CHARACTER_TYPE_MAX_VALUE;
|
|
|
|
hash.insert(hash.begin(), sentenceBoundaryHI);
|
|
|
|
hash.push_back(sentenceBoundaryHI);
|
|
|
|
|
|
|
|
saidx_t patternLength = hash.size()*sizeof(INDEX_CHARACTER_TYPE);
|
|
|
|
sauchar_t * patternArray = Utils::indexVectorToSaucharArray(hash);
|
|
|
|
|
|
|
|
int size = sa_search(T->data(), (saidx_t) T->size(),
|
|
|
|
(const sauchar_t *) patternArray, patternLength,
|
|
|
|
SA->data(), (saidx_t) SA->size(), &left);
|
|
|
|
|
|
|
|
// In this scenario the whole pattern is matched, but
|
|
|
|
// the pattern was artificially augmented by two EOS's.
|
|
|
|
// Therefore, the matched pattern fragment starts at 0
|
|
|
|
// and is hash.size() - 2 long.
|
|
|
|
MatchedPatternFragment result(0, hash.size()-2);
|
|
|
|
for (int i = 0; i < size; ++i) {
|
|
|
|
saidx_t resultPos = SA->at(left + i);
|
|
|
|
if (resultPos % sizeof(INDEX_CHARACTER_TYPE) == 0) {
|
|
|
|
// As we are looking for a pattern in an array of higher
|
|
|
|
// resolution than the hashed index file, we might
|
|
|
|
// obtain accidental results exceeding the boundaries
|
|
|
|
// of characters in hashed index. The above check
|
|
|
|
// removes these accidental results.
|
|
|
|
saidx_t actualResultPos = resultPos / sizeof(INDEX_CHARACTER_TYPE);
|
|
|
|
|
|
|
|
// Our search query started with an EOS and is non-empty,
|
|
|
|
// so we should look at the marker of the next character
|
|
|
|
SUFFIX_MARKER_TYPE marker = markers->at(actualResultPos + 1);
|
|
|
|
|
|
|
|
SubstringOccurence occurence;
|
|
|
|
occurence.enterDataFromMarker(marker);
|
|
|
|
result.addOccurence(occurence);
|
|
|
|
if (result.getOccurences().size() >= CONCORDIA_SEARCH_MAX_RESULTS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] patternArray;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-10-01 13:36:54 +02:00
|
|
|
SUFFIX_MARKER_TYPE IndexSearcher::countOccurences(
|
|
|
|
boost::shared_ptr<HashGenerator> hashGenerator,
|
|
|
|
boost::shared_ptr<std::vector<sauchar_t> > T,
|
|
|
|
boost::shared_ptr<std::vector<SUFFIX_MARKER_TYPE> > markers,
|
|
|
|
boost::shared_ptr<std::vector<saidx_t> > SA,
|
|
|
|
const std::string & pattern) throw(ConcordiaException) {
|
|
|
|
int left;
|
|
|
|
std::vector<INDEX_CHARACTER_TYPE> hash =
|
|
|
|
hashGenerator->generateHash(pattern).getCodes();
|
|
|
|
|
2015-10-16 22:14:11 +02:00
|
|
|
// append sentence boundary marker,
|
|
|
|
// as we are looking only for exact sentence matches
|
2015-10-01 13:36:54 +02:00
|
|
|
hash.push_back(INDEX_CHARACTER_TYPE_MAX_VALUE);
|
2015-10-16 22:14:11 +02:00
|
|
|
|
2015-10-01 13:36:54 +02:00
|
|
|
saidx_t patternLength = hash.size()*sizeof(INDEX_CHARACTER_TYPE);
|
|
|
|
sauchar_t * patternArray = Utils::indexVectorToSaucharArray(hash);
|
|
|
|
|
|
|
|
int size = sa_search(T->data(), (saidx_t) T->size(),
|
|
|
|
(const sauchar_t *) patternArray, patternLength,
|
|
|
|
SA->data(), (saidx_t) SA->size(), &left);
|
2015-10-16 22:14:11 +02:00
|
|
|
|
2015-10-01 13:36:54 +02:00
|
|
|
SUFFIX_MARKER_TYPE occurencesCount = 0;
|
|
|
|
for (int i = 0; i < size; ++i) {
|
|
|
|
saidx_t resultPos = SA->at(left + i);
|
|
|
|
if (resultPos % sizeof(INDEX_CHARACTER_TYPE) == 0) {
|
|
|
|
// As we are looking for a pattern in an array of higher
|
|
|
|
// resolution than the hashed index file, we might
|
|
|
|
// obtain accidental results exceeding the boundaries
|
|
|
|
// of characters in hashed index. The above check
|
|
|
|
// removes these accidental results.
|
|
|
|
occurencesCount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] patternArray;
|
2015-10-16 22:14:11 +02:00
|
|
|
|
2015-10-01 13:36:54 +02:00
|
|
|
return occurencesCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-15 14:14:10 +02:00
|
|
|
std::vector<AnubisSearchResult> IndexSearcher::anubisSearch(
|
2015-04-16 11:39:39 +02:00
|
|
|
boost::shared_ptr<ConcordiaConfig> config,
|
2014-03-11 14:29:30 +01:00
|
|
|
boost::shared_ptr<HashGenerator> hashGenerator,
|
|
|
|
boost::shared_ptr<std::vector<sauchar_t> > T,
|
|
|
|
boost::shared_ptr<std::vector<SUFFIX_MARKER_TYPE> > markers,
|
|
|
|
boost::shared_ptr<std::vector<saidx_t> > SA,
|
2015-04-15 14:14:10 +02:00
|
|
|
const std::string & pattern) throw(ConcordiaException) {
|
|
|
|
std::vector<INDEX_CHARACTER_TYPE> hash =
|
2015-08-19 20:49:26 +02:00
|
|
|
hashGenerator->generateHash(pattern).getCodes();
|
2015-04-24 11:48:32 +02:00
|
|
|
return _concordiaSearcher->anubisSearch(config, T, markers, SA, hash);
|
2014-03-11 14:29:30 +01:00
|
|
|
}
|
2015-04-17 14:17:59 +02:00
|
|
|
|
|
|
|
boost::shared_ptr<ConcordiaSearchResult> IndexSearcher::concordiaSearch(
|
|
|
|
boost::shared_ptr<HashGenerator> hashGenerator,
|
|
|
|
boost::shared_ptr<std::vector<sauchar_t> > T,
|
|
|
|
boost::shared_ptr<std::vector<SUFFIX_MARKER_TYPE> > markers,
|
|
|
|
boost::shared_ptr<std::vector<saidx_t> > SA,
|
2017-04-22 23:45:51 +02:00
|
|
|
const std::string & pattern,
|
|
|
|
bool byWhitespace) throw(ConcordiaException) {
|
2017-04-22 23:47:48 +02:00
|
|
|
TokenizedSentence hashedPattern =
|
|
|
|
hashGenerator->generateHash(pattern, byWhitespace);
|
2015-04-17 14:17:59 +02:00
|
|
|
boost::shared_ptr<ConcordiaSearchResult> result =
|
|
|
|
boost::shared_ptr<ConcordiaSearchResult>(
|
2015-06-26 22:50:53 +02:00
|
|
|
new ConcordiaSearchResult(hashedPattern));
|
2015-04-17 14:17:59 +02:00
|
|
|
|
2015-06-27 12:40:24 +02:00
|
|
|
_concordiaSearcher->concordiaSearch(result, T, markers,
|
2015-08-19 20:49:26 +02:00
|
|
|
SA, hashedPattern.getCodes());
|
2015-04-17 14:17:59 +02:00
|
|
|
return result;
|
|
|
|
}
|