diff --git a/src/lib/data/search/SearchIndex.cpp b/src/lib/data/search/SearchIndex.cpp index 5cd499e6..b2367f63 100644 --- a/src/lib/data/search/SearchIndex.cpp +++ b/src/lib/data/search/SearchIndex.cpp @@ -100,7 +100,7 @@ void SearchIndex::clear() } std::vector SearchIndex::search( - const std::string& query, Node::NodeTypeMask filter, size_t maxResultCount, size_t maxBestScoredLength) const + const std::string& query, Node::NodeTypeMask filter, size_t maxResultCount, size_t maxBestScoredResultsLength) const { // find paths containing query SearchPath startPath; @@ -110,14 +110,14 @@ std::vector SearchIndex::search( searchRecursive(startPath, utility::toLowerCase(query), filter, &paths); // create scored search results - std::multiset searchResults = createScoredResults(paths, filter, maxResultCount * 3); + std::multiset searchResults = createScoredResults(paths, filter, maxResultCount * 2); // find best scores std::map scoresCache; std::multiset bestResults; for (const SearchResult& result : searchResults) { - bestResults.insert(bestScoredResult(result, &scoresCache, maxBestScoredLength)); + bestResults.insert(bestScoredResult(result, &scoresCache, maxBestScoredResultsLength)); } // narrow down to max result count @@ -147,7 +147,8 @@ void SearchIndex::populateEdgeGate(SearchEdge* e) } void SearchIndex::searchRecursive( - const SearchPath& path, const std::string& remainingQuery, Node::NodeTypeMask filter, std::vector* results) const + const SearchPath& path, const std::string& remainingQuery, Node::NodeTypeMask filter, + std::vector* results) const { if (remainingQuery.size() == 0 && (!filter || (path.node->mask & filter))) { @@ -200,16 +201,10 @@ std::multiset SearchIndex::createScoredResults( const std::vector& paths, Node::NodeTypeMask filter, size_t maxResultCount) const { // score and order initial paths - std::multiset, bool(*)(const std::pair&, const std::pair&)> scoredPaths( - [](const std::pair& a, const std::pair& b) - { - return a.first > b.first; - } - ); - + std::multimap> scoredPaths; for (const SearchPath& path : paths) { - scoredPaths.insert(std::make_pair(scoreText(path.text, path.indices), path)); + scoredPaths.emplace(scoreText(path.text, path.indices), path); } // score paths and subpaths @@ -259,13 +254,8 @@ std::multiset SearchIndex::createScoredResults( } SearchResult SearchIndex::bestScoredResult( - SearchResult result, std::map* scoresCache, size_t maxBestScoredLength) + SearchResult result, std::map* scoresCache, size_t maxBestScoredResultsLength) { - if (maxBestScoredLength && result.text.size() > maxBestScoredLength) - { - return result; - } - const std::vector indices = result.indices; int oldScore = result.score; @@ -281,13 +271,24 @@ SearchResult SearchIndex::bestScoredResult( if (!consecutive) { - bestScoredResultRecursive(utility::toLowerCase(result.text), indices, indices.size() - 1, scoresCache, &result); + std::string lowerText = utility::toLowerCase(result.text); + if (maxBestScoredResultsLength && lowerText.size() > maxBestScoredResultsLength) + { + if (indices.back() >= maxBestScoredResultsLength) + { + return result; + } + + lowerText = lowerText.substr(0, maxBestScoredResultsLength); + } + + bestScoredResultRecursive(lowerText, indices, indices.size() - 1, scoresCache, &result); } std::string subtext = result.text.substr(0, result.indices.back() + 1); if (result.score != oldScore || scoresCache->find(subtext) == scoresCache->end()) { - scoresCache->emplace(subtext, result); + scoresCache->operator[](subtext) = result; } return result; @@ -340,7 +341,7 @@ void SearchIndex::bestScoredResultRecursive( if (indicesPos + 1 == indices.size()) { std::map::const_iterator it = scoresCache->find(result->text.substr(0, indices.back() + 1)); - if (it != scoresCache->end()) + if (it != scoresCache->end() && it->second.score > result->score) { result->score = it->second.score; result->indices = it->second.indices; @@ -364,7 +365,7 @@ void SearchIndex::bestScoredResultRecursive( int SearchIndex::scoreText(const std::string& text, const std::vector& indices) { const int unmatchedLetterBonus = -1; - const int consecutiveLetterBonus = 5; + const int consecutiveLetterBonus = 4; const int camelCaseBonus = 4; const int noLetterBonus = 3; const int firstLetterBonus = 4; @@ -391,13 +392,23 @@ int SearchIndex::scoreText(const std::string& text, const std::vector& i noLetters.insert('\\'); } + size_t consecutiveLetterCount = 0; for (size_t i = 0; i < indices.size(); i++) { // unmatched and consecutive if (i > 0) { unmatchedLetterScore += (indices[i] - indices[i - 1] - 1) * unmatchedLetterBonus; - consecutiveLetterScore += (indices[i] - indices[i - 1] == 1 ? consecutiveLetterBonus : 0); + + if (indices[i] - indices[i - 1] == 1) + { + consecutiveLetterCount++; + consecutiveLetterScore += consecutiveLetterBonus * consecutiveLetterCount; + } + else + { + consecutiveLetterCount = 0; + } } size_t index = indices[i]; @@ -443,7 +454,7 @@ SearchResult SearchIndex::rescoreText( const std::string& text, const std::vector& indices, int score, - size_t maxBestScoredLength) + size_t maxBestScoredResultsLength) { SearchResult result; result.text = text; @@ -461,16 +472,17 @@ SearchResult SearchIndex::rescoreText( textIndices.push_back(idx - (fulltext.size() - text.size())); } } - // ignore rescoring if result is too long - else if (maxBestScoredLength > 0 && fulltext.size() > maxBestScoredLength * 2) - { - return result; - } // try if match is within text else { size_t idx = 0; - for (size_t i = 0; i < text.size() && idx < indices.size(); i++) + size_t textSize = text.size(); + if (maxBestScoredResultsLength && textSize > maxBestScoredResultsLength) + { + textSize = maxBestScoredResultsLength; + } + + for (size_t i = 0; i < textSize && idx < indices.size(); i++) { if (tolower(text[i]) == tolower(fulltext[indices[idx]])) { @@ -491,7 +503,7 @@ SearchResult SearchIndex::rescoreText( result.indices = textIndices; std::map scoresCache; - result = bestScoredResult(result, &scoresCache, maxBestScoredLength); + result = bestScoredResult(result, &scoresCache, maxBestScoredResultsLength); for (size_t i = 0; i < result.indices.size(); i++) { diff --git a/src/lib/data/search/SearchIndex.h b/src/lib/data/search/SearchIndex.h index f678a5a6..3e85384a 100644 --- a/src/lib/data/search/SearchIndex.h +++ b/src/lib/data/search/SearchIndex.h @@ -35,7 +35,8 @@ public: void clear(); // maxResultCount == 0 means "no restriction". - std::vector search(const std::string& query, Node::NodeTypeMask filter, size_t maxResultCount, size_t maxBestScoredLength = 0) const; + std::vector search( + const std::string& query, Node::NodeTypeMask filter, size_t maxResultCount, size_t maxBestScoredResultsLength = 0) const; private: struct SearchEdge; @@ -69,7 +70,7 @@ private: const std::vector& paths, Node::NodeTypeMask filter, size_t maxResultCount) const; static SearchResult bestScoredResult( - SearchResult result, std::map* scoresCache, size_t maxBestScoredLength); + SearchResult result, std::map* scoresCache, size_t maxBestScoredResultsLength); static void bestScoredResultRecursive( const std::string& lowerText, const std::vector& indices, const size_t indicesPos, std::map* scoresCache, SearchResult* result); @@ -81,7 +82,7 @@ public: const std::string& text, const std::vector& indices, int score, - size_t maxBestScoredLength); + size_t maxBestScoredResultsLength); private: std::vector> m_nodes; diff --git a/src/lib/data/storage/PersistentStorage.cpp b/src/lib/data/storage/PersistentStorage.cpp index 07cb043f..18033511 100644 --- a/src/lib/data/storage/PersistentStorage.cpp +++ b/src/lib/data/storage/PersistentStorage.cpp @@ -587,7 +587,7 @@ std::vector PersistentStorage::getAutocompletionMatches(const std:: TRACE(); // search in indices - size_t maxResultsCount = 100; + size_t maxResultsCount = 500; size_t maxBestScoredResultsLength = 100; // create SearchMatches @@ -595,7 +595,7 @@ std::vector PersistentStorage::getAutocompletionMatches(const std:: if (!filter || (filter & ~Node::NODE_FILE)) { - utility::append(matches, getAutocompletionSymbolMatches(query, filter, maxResultsCount)); + utility::append(matches, getAutocompletionSymbolMatches(query, filter, maxResultsCount, maxBestScoredResultsLength)); } if (!filter || (filter & Node::NODE_FILE)) @@ -621,14 +621,20 @@ std::vector PersistentStorage::getAutocompletionMatches(const std:: matchesSet.insert(match); } + // for (auto a : matchesSet) + // { + // std::cout << a.score << " " << a.name << std::endl; + // } + return utility::toVector(matchesSet); } std::vector PersistentStorage::getAutocompletionSymbolMatches( - const std::string& query, Node::NodeTypeMask filter, size_t maxResultsCount) const + const std::string& query, Node::NodeTypeMask filter, size_t maxResultsCount, size_t maxBestScoredResultsLength) const { // search in indices - std::vector results = m_symbolIndex.search(query, filter, maxResultsCount, maxResultsCount); + std::vector results = + m_symbolIndex.search(query, filter, maxResultsCount, maxBestScoredResultsLength); // fetch StorageNodes for node ids std::map storageNodeMap; @@ -2500,7 +2506,8 @@ void PersistentStorage::buildSearchIndex() else { auto it = m_symbolDefinitionKinds.find(node.id); - if (it == m_symbolDefinitionKinds.end() || it->second != DEFINITION_IMPLICIT) + DefinitionKind defKind = (it != m_symbolDefinitionKinds.end() ? it->second : DEFINITION_NONE); + if (defKind != DEFINITION_IMPLICIT) { NameHierarchy nameHierarchy = NameHierarchy::deserialize(node.serializedName); @@ -2509,7 +2516,7 @@ void PersistentStorage::buildSearchIndex() // replace template arguments with .. to avoid clutter in search results and have different // template specializations share the same node. - if (it->second == DEFINITION_NONE && nameHierarchy.getDelimiter() == NAME_DELIMITER_CXX) + if (defKind == DEFINITION_NONE && nameHierarchy.getDelimiter() == NAME_DELIMITER_CXX) { name = utility::replaceBetween(name, '<', '>', ".."); } diff --git a/src/lib/data/storage/PersistentStorage.h b/src/lib/data/storage/PersistentStorage.h index 41e92fd6..25cab317 100644 --- a/src/lib/data/storage/PersistentStorage.h +++ b/src/lib/data/storage/PersistentStorage.h @@ -89,7 +89,7 @@ public: virtual std::vector getAutocompletionMatches(const std::string& query, Node::NodeTypeMask filter) const; std::vector getAutocompletionSymbolMatches( - const std::string& query, Node::NodeTypeMask filter, size_t maxResultsCount) const; + const std::string& query, Node::NodeTypeMask filter, size_t maxResultsCount, size_t maxBestScoredResultsLength) const; std::vector getAutocompletionFileMatches(const std::string& query, size_t maxResultsCount) const; std::vector getAutocompletionCommandMatches(const std::string& query, Node::NodeTypeMask filter) const; virtual std::vector getSearchMatchesForTokenIds(const std::vector& elementIds) const;