Ticket #128: qp_exact_text.patch
File qp_exact_text.patch, 6.7 KB (added by , 18 years ago) |
---|
-
xapian-bindings/xapian.i
955 955 Query parse_query(const string &q, unsigned flags); 956 956 957 957 void add_prefix(const std::string &field, const std::string &prefix); 958 void add_exact_prefix(const std::string &field, const std::string &prefix); 958 959 void add_boolean_prefix(const std::string & field, const std::string &prefix); 959 960 960 961 TermIterator stoplist_begin() const; -
xapian-core/queryparser/queryparser.lemony
461 461 new Term(prefix, 0), &state); 462 462 continue; 463 463 } 464 465 if (type == PrefixInfo::EXACT_TEXT) { 466 it = p; 467 if (prefix_needs_colon(prefix, *it)) 468 prefix += ':'; 469 field += ':'; 470 string term; 464 471 472 if (*it == '"') { 473 // Quoted term: continue until unescaped end quote 474 field += *it; 475 ++it; 476 while (it != end && *it != '"') { 477 field += *it; 478 if (*it == '\\') { 479 ++it; 480 if (it == end) { 481 term.append(ubuf, to_utf8('\\' , ubuf)); 482 } else if (*it == '"' || *it == '\\') { 483 term.append(ubuf, to_utf8(*it++, ubuf)); 484 } else { 485 term.append(ubuf, to_utf8('\\' , ubuf)); 486 term.append(ubuf, to_utf8(*it++, ubuf)); 487 } 488 } else { 489 term.append(ubuf, to_utf8(*it++, ubuf)); 490 } 491 } 492 if (it != end) 493 ++it; 494 } else { 495 // Non-quoted term: continue until space or ')'. 496 while (it != end && *it > ' ' && *it != ')') 497 term.append(ubuf, to_utf8(*it++, ubuf)); 498 field += term; 499 } 500 501 prefix += term; 502 unstem.insert(make_pair(prefix, field)); 503 Parse(pParser, TERM, 504 new Term(prefix, term_pos++), &state); 505 continue; 506 } 507 465 508 Assert(type == PrefixInfo::FREE_TEXT); 466 509 467 510 if (ch == '"' && (flags & FLAG_PHRASE)) { … … 475 518 continue; 476 519 } 477 520 521 478 522 if (ch == '(' && (flags & FLAG_BOOLEAN)) { 479 523 // Prefixed subexpression, e.g.: title:(fast NEAR food) 480 524 Parse(pParser, BRA, NULL, &state); … … 938 982 if (P->hate.can_match()) { 939 983 if (E->empty()) { 940 984 delete E; 941 // Can't just hate! 942 yy_parse_failed(yypParser); 943 return; 985 if (state->flags & QueryParser::FLAG_PURE_NOT) { 986 E = new QpQuery("", 1, 0); 987 } else { 988 // Can't just hate! 989 yy_parse_failed(yypParser); 990 return; 991 } 944 992 } 945 993 *E = QpQuery(Query::OP_AND_NOT, *E, P->hate); 946 994 } -
xapian-core/queryparser/queryparser_internal.h
37 37 struct PrefixInfo { 38 38 typedef enum { 39 39 FREE_TEXT, 40 EXACT_TEXT, 40 41 BOOL_FILTER 41 42 } prefix_type; 42 43 PrefixInfo::prefix_type type; -
xapian-core/queryparser/queryparser.cc
130 130 } 131 131 132 132 void 133 QueryParser::add_exact_prefix(const std::string &field, 134 const std::string &prefix) 135 { 136 internal->prefixes.insert( 137 make_pair(field, PrefixInfo(PrefixInfo::EXACT_TEXT, prefix))); 138 } 139 140 void 133 141 QueryParser::add_boolean_prefix(const std::string &field, 134 142 const std::string &prefix) 135 143 { -
xapian-core/tests/queryparsertest.cc
87 87 { "-site:xapian.org mail", "(mail:(pos=1) AND_NOT Hxapian.org)" }, 88 88 { "site:xapian.org", "Hxapian.org" }, 89 89 { "mug +site:xapian.org -site:cvs.xapian.org", "((mug:(pos=1) AND_NOT Hcvs.xapian.org) FILTER Hxapian.org)" }, 90 { "exact:xapian.org exact:cvs.xapian.org", "(Exapian.org:(pos=1) OR Ecvs.xapian.org:(pos=2))" }, 91 { "+exact:xapian.org -exact:cvs.xapian.org", "(Exapian.org:(pos=1) AND_NOT Ecvs.xapian.org:(pos=2))" }, 92 { "-exact:cvs.xapian.org", "Ecvs.xapian.org:(pos=1)" }, 93 { "mug +exact:xapian.org", "(Exapian.org:(pos=2) AND_MAYBE mug:(pos=1))" }, 90 94 { "mug -site:cvs.xapian.org +site:xapian.org", "((mug:(pos=1) AND_NOT Hcvs.xapian.org) FILTER Hxapian.org)" }, 91 95 { "NOT windows", "Syntax: <expression> NOT <expression>" }, 92 96 { "a AND (NOT b)", "Syntax: <expression> NOT <expression>" }, … … 564 568 { "AND NOT windows", "Syntax: <expression> AND NOT <expression>" }, 565 569 { "gordian NOT", "Syntax: <expression> NOT <expression>" }, 566 570 { "gordian AND NOT", "Syntax: <expression> AND NOT <expression>" }, 571 { "NOT exact:cvs.xapian.org", "(<alldocuments> AND_NOT Ecvs.xapian.org:(pos=1))" }, 572 { "-exact:cvs.xapian.org", "(<alldocuments> AND_NOT Ecvs.xapian.org:(pos=1))" }, 573 { "-exact:\"hello world\"", "(<alldocuments> AND_NOT Ehello world:(pos=1))" }, 574 { "-exact:help", "(<alldocuments> AND_NOT Ehelp:(pos=1))" }, 567 575 { NULL, NULL } 568 576 }; 569 577 … … 576 584 queryparser.add_prefix("title", "XT"); 577 585 queryparser.add_prefix("subject", "XT"); 578 586 queryparser.add_boolean_prefix("site", "H"); 587 queryparser.add_exact_prefix("exact", "E"); 579 588 for (test *p = test_or_queries; p->query; ++p) { 580 589 string expect, parsed; 581 590 if (p->expect) … … 845 854 Xapian::QueryParser qp; 846 855 qp.set_stemmer(Xapian::Stem("english")); 847 856 qp.set_stemming_strategy(QueryParser::STEM_SOME); 857 qp.add_exact_prefix("exact", "E"); 848 858 for (test *p = test_pure_not_queries; p->query; ++p) { 849 859 string expect, parsed; 850 860 if (p->expect) … … 854 864 try { 855 865 Xapian::Query qobj = qp.parse_query(p->query, 856 866 QueryParser::FLAG_BOOLEAN | 857 QueryParser::FLAG_PURE_NOT); 867 QueryParser::FLAG_PURE_NOT | 868 QueryParser::FLAG_LOVEHATE); 858 869 parsed = qobj.get_description(); 859 870 expect = string("Xapian::Query(") + expect + ')'; 860 871 } catch (const Xapian::Error &e) { -
xapian-core/include/xapian/queryparser.h
228 228 */ 229 229 void add_prefix(const std::string &field, const std::string &prefix); 230 230 231 /** 232 */ 233 void add_exact_prefix(const std::string &field, const std::string &prefix); 234 231 235 /** Add a boolean term prefix allowing the user to restrict a 232 236 * search with a boolean filter specified in the free text query. 233 237 *