From 107e02b74a465f303021fdc5596333a29bc883db Mon Sep 17 00:00:00 2001 From: Jean-Francois Dockes Date: Tue, 21 Dec 2010 16:00:25 +0100 Subject: [PATCH] Gui search: make autophrase work with a query language query --- src/qtgui/ssearch_w.cpp | 3 ++ src/rcldb/searchdata.cpp | 68 ++++++++++++++++++++++++++++++++++++++-- src/rcldb/searchdata.h | 14 ++++++++- 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/src/qtgui/ssearch_w.cpp b/src/qtgui/ssearch_w.cpp index f98dfa06..5fe8aaf5 100644 --- a/src/qtgui/ssearch_w.cpp +++ b/src/qtgui/ssearch_w.cpp @@ -139,6 +139,9 @@ void SSearch::startSimpleSearch() QString::fromAscii(reason.c_str())); return; } + if (prefs.ssearchAutoPhrase) { + sdata->maybeAddAutoPhrase(); + } } else { sdata = new Rcl::SearchData(Rcl::SCLT_OR); if (sdata == 0) { diff --git a/src/rcldb/searchdata.cpp b/src/rcldb/searchdata.cpp index 0d8f3828..4c58a5b1 100644 --- a/src/rcldb/searchdata.cpp +++ b/src/rcldb/searchdata.cpp @@ -242,7 +242,7 @@ bool SearchData::toNativeQuery(Rcl::Db &db, void *d) for (vector::iterator it = exptps.begin(); it != exptps.end(); it++) { string term = "T" + *it; - LOGDEB(("Adding file type term: [%s]\n", term.c_str())); + LOGDEB0(("Adding file type term: [%s]\n", term.c_str())); tq = tq.empty() ? Xapian::Query(term) : Xapian::Query(Xapian::Query::OP_OR, tq, Xapian::Query(term)); } @@ -268,6 +268,70 @@ bool SearchData::toNativeQuery(Rcl::Db &db, void *d) return true; } + +bool SearchData::maybeAddAutoPhrase() +{ + LOGDEB0(("SearchData::maybeAddAutoPhrase()\n")); + if (!m_query.size()) { + LOGDEB2(("SearchData::maybeAddAutoPhrase: empty query\n")); + return false; + } + + string field; + string words; + // Walk the clause list. If we find any non simple clause or different + // field names, bail out. + for (qlist_it_t it = m_query.begin(); it != m_query.end(); it++) { + SClType tp = (*it)->m_tp; + if (tp != SCLT_AND && tp != SCLT_OR) { + LOGDEB2(("SearchData::maybeAddAutoPhrase: complex clause\n")); + return false; + } + SearchDataClauseSimple *clp = + dynamic_cast(*it); + if (clp == 0) { + LOGDEB2(("SearchData::maybeAddAutoPhrase: dyncast failed\n")); + return false; + } + if (it == m_query.begin()) { + field = clp->getfield(); + } else { + if (clp->getfield().compare(field)) { + LOGDEB2(("SearchData::maybeAddAutoPhrase: different fields\n")); + return false; + } + } + if (!words.empty()) + words += " "; + words += clp->gettext(); + } + + if (words.find_first_of("\"*[]?") != string::npos && // has wildcards + TextSplit::countWords(words) <= 1) { // Just one word. + LOGDEB2(("SearchData::maybeAddAutoPhrase: wildcards or single word\n")); + return false; + } + + SearchDataClauseDist *nclp = + new SearchDataClauseDist(SCLT_PHRASE, words, 0, field); + if (m_tp == SCLT_OR) { + addClause(nclp); + } else { + // My type is AND. Change it to OR and insert two queries, one + // being the original query as a subquery, the other the + // phrase. + SearchData *sd = new SearchData(m_tp); + sd->m_query = m_query; + m_tp = SCLT_OR; + m_query.clear(); + SearchDataClauseSub *oq = + new SearchDataClauseSub(SCLT_OR, RefCntr(sd)); + addClause(oq); + addClause(nclp); + } + return true; +} + // Add clause to current list. OR lists cant have EXCL clauses. bool SearchData::addClause(SearchDataClause* cl) { @@ -284,7 +348,7 @@ bool SearchData::addClause(SearchDataClause* cl) // Make me all new void SearchData::erase() { - LOGDEB(("SearchData::erase\n")); + LOGDEB0(("SearchData::erase\n")); m_tp = SCLT_AND; for (qlist_it_t it = m_query.begin(); it != m_query.end(); it++) delete *it; diff --git a/src/rcldb/searchdata.h b/src/rcldb/searchdata.h index 9c0f9502..29a1f0cd 100644 --- a/src/rcldb/searchdata.h +++ b/src/rcldb/searchdata.h @@ -73,7 +73,10 @@ class SearchData { public: SearchData(SClType tp) : m_tp(tp), m_haveDates(false), m_haveWildCards(false) - {} + { + if (m_tp != SCLT_OR && m_tp != SCLT_AND) + m_tp = SCLT_OR; + } ~SearchData() {erase();} /** Make pristine */ @@ -91,6 +94,13 @@ public: /** We become the owner of cl and will delete it */ bool addClause(SearchDataClause *cl); + /** If this is a simple query (one field only, no distance clauses), + add phrase made of query terms to query, so that docs containing the + user terms in order will have higher relevance. This must be called + before toNativeQuery(). + */ + bool maybeAddAutoPhrase(); + /** Set/get top subdirectory for filtering results */ void setTopdir(const string& t) {m_topdir = t;} string getTopdir() {return m_topdir;} @@ -207,6 +217,8 @@ public: { terms.insert(terms.end(), m_uterms.begin(), m_uterms.end()); } + virtual const string& gettext() {return m_text;} + virtual const string& getfield() {return m_field;} protected: string m_text; // Raw user entry text. string m_field; // Field specification if any