Files

537 lines
17 KiB
C
Raw Permalink Normal View History

2013-08-02 13:12:24 -07:00
// Matt Wells, copyright Aug 2003
// Query is a class for parsing queries
2016-03-08 22:14:30 +01:00
#ifndef GB_QUERY_H
#define GB_QUERY_H
2013-08-02 13:12:24 -07:00
#include "SafeBuf.h"
2015-07-13 14:59:44 -06:00
// support big OR queries for image shingles
#define ABS_MAX_QUERY_LEN 62000
2016-02-25 16:11:45 +01:00
// raise for crazy bool query on diffbot
// seems like we alloc just enough to hold our words now so that this
// is really a performance capper but it is used in Summary.cpp
// and Matches.h so don't go too big just yet
#define ABS_MAX_QUERY_WORDS 99000
2013-08-02 13:12:24 -07:00
// . how many IndexLists might we get/intersect
2014-10-30 13:36:39 -06:00
// . we now use a int64_t to hold the query term bits for non-boolean queries
#define ABS_MAX_QUERY_TERMS 9000
2013-08-02 13:12:24 -07:00
#define GBUF_SIZE (16*1024)
// let's support up to 64 query terms for now
typedef uint64_t qvec_t;
2013-08-02 13:12:24 -07:00
#define MAX_EXPLICIT_BITS (sizeof(qvec_t)*8)
2014-03-13 13:09:33 -07:00
#define MAX_OVEC_SIZE 256
2013-08-02 13:12:24 -07:00
// field codes
enum field_code_t {
FIELD_UNSET = 0,
FIELD_URL = 1,
FIELD_LINK = 2,
FIELD_SITE = 3,
FIELD_IP = 4,
FIELD_SUBURL = 5,
FIELD_TITLE = 6,
FIELD_TYPE = 7,
FIELD_EXT = 21,
//FIELD_COLL = 22,
FIELD_ILINK = 23,
FIELD_LINKS = 24,
FIELD_SITELINK = 25,
// non-standard field codes
FIELD_ZIP = 8,
//FIELD_UNUSED = 9,
//FIELD_UNUSED = 10,
//FIELD_UNUSED = 11,
//FIELD_UNUSED = 12,
//FIELD_UNUSED = 13,
//FIELD_UNUSED = 14,
//FIELD_UNUSED = 15,
//FIELD_UNUSED = 16,
//FIELD_UNUSED = 17,
FIELD_GENERIC = 18,
FIELD_ISCLEAN = 19, // we hash field="isclean:" val="1" if doc clean
//FIELD_UNUSED = 20,
FIELD_CHARSET = 30,
FIELD_GBRSS = 31,
//FIELD_UNUSED = 32,
//FIELD_UNUSED = 33,
//FIELD_UNUSED = 34,
//FIELD_UNUSED = 35,
FIELD_GBLANG = 36,
//FIELD_UNUSED = 37,
//FIELD_UNUSED = 38,
//FIELD_UNUSED = 39,
//FIELD_UNUSED = 40,
//FIELD_UNUSED = 41,
//FIELD_UNUSED = 42,
//FIELD_UNUSED = 43,
//FIELD_UNUSED = 44,
//FIELD_UNUSED = 45,
FIELD_GBCOUNTRY = 46,
//FIELD_UNUSED = 47,
//FIELD_UNUSED = 48,
FIELD_GBPERMALINK = 49,
//FIELD_UNUSED = 50,
FIELD_GBTERMID = 50,
//FIELD_UNUSED = 51,
FIELD_GBDOCID = 52,
FIELD_GBCONTENTHASH = 53, // for deduping at spider time
FIELD_GBSORTBYFLOAT = 54, // i.e. sortby:price -> numeric termlist
FIELD_GBREVSORTBYFLOAT = 55, // i.e. sortby:price -> low to high
FIELD_GBNUMBERMIN = 56,
FIELD_GBNUMBERMAX = 57,
FIELD_GBPARENTURL = 58,
FIELD_GBSORTBYINT = 59,
FIELD_GBREVSORTBYINT = 60,
FIELD_GBNUMBERMININT = 61,
FIELD_GBNUMBERMAXINT = 62,
//FIELD_UNUSED = 63,
//FIELD_UNUSED = 64,
//FIELD_UNUSED = 65,
FIELD_GBNUMBEREQUALINT = 66,
FIELD_GBNUMBEREQUALFLOAT= 67,
FIELD_SUBURL2 = 68,
FIELD_GBFIELDMATCH = 69,
};
2013-08-02 13:12:24 -07:00
// returns a FIELD_* code above, or FIELD_GENERIC if not in the list
field_code_t getFieldCode(const char *s, int32_t len, bool *hasColon = NULL);
2013-08-02 13:12:24 -07:00
2014-11-10 14:45:11 -08:00
int32_t getNumFieldCodes ( );
2013-08-02 13:12:24 -07:00
2016-09-19 12:32:26 +02:00
class Query;
class ScoringWeights;
2016-09-19 12:32:26 +02:00
// . values for QueryField::m_flag
// . QTF_DUP means it is just for the help page in PageRoot.cpp to
// illustrate a second or third example
2014-08-08 07:48:11 -07:00
#define QTF_DUP 0x01
#define QTF_HIDE 0x02
2014-08-27 23:10:27 -06:00
#define QTF_BEGINNEWTABLE 0x04
2013-08-02 13:12:24 -07:00
struct QueryField {
const char *text;
field_code_t field;
2013-08-02 13:12:24 -07:00
bool hasColon;
const char *example;
const char *desc;
const char *m_title;
char m_flag;
2013-08-02 13:12:24 -07:00
};
2017-05-09 14:50:17 +02:00
extern const struct QueryField g_fields[];
2013-08-02 13:12:24 -07:00
// reasons why we ignore a particular QueryWord's word or phrase
enum ignore_reason_t {
IGNORE_NO_IGNORE = 0,
IGNORE_DEFAULT = 1, // punct
IGNORE_CONNECTED = 2, // connected sequence (cd-rom)
IGNORE_QSTOP = 3, // query stop word (come 'to' me)
IGNORE_REPEAT = 4, // repeated term (time after time)
IGNORE_FIELDNAME = 5, // word is a field name, like title:
IGNORE_BREECH = 6, // query exceeded MAX_QUERY_TERMS so we ignored part
IGNORE_BOOLOP = 7, // boolean operator (OR,AND,NOT)
IGNORE_QUOTED = 8, // word in quotes is ignored. "the day"
IGNORE_HIGHFREMTERM = 9 //trem(word) is a high-freq-term and is too expensive to look up
};
2013-08-02 13:12:24 -07:00
// boolean query operators (m_opcode field in QueryWord)
#define OP_OR 1
#define OP_AND 2
#define OP_NOT 3
#define OP_LEFTPAREN 4
#define OP_RIGHTPAREN 5
#define OP_UOR 6
#define OP_PIPE 7
// . these first two classes are functionless
// . QueryWord, like the Phrases class, is an extension on the Words class
// . the array of QueryWords, m_qwords[], is contained in the Query class
// . we compute the QueryTerms (m_qterms[]) from the QueryWords
class QueryWord {
public:
2017-02-14 11:32:24 +01:00
bool isAlphaWord() const { return is_alnum_utf8(m_word); }
2016-03-01 16:42:49 +01:00
2015-07-13 17:47:34 -06:00
void constructor ();
void destructor ();
2013-08-02 13:12:24 -07:00
// this ptr references into the actual query
char *m_word ;
2014-11-10 14:45:11 -08:00
int32_t m_wordLen ;
// the length of the phrase, if any. it starts at m_word. It can be less than the source string length because
// non-alfanum words are treated as a single space by Phrases::getPhrase(), so eg "aaa::bbb" will only have m_phraseLen=7
2014-11-10 14:45:11 -08:00
int32_t m_phraseLen;
2013-08-02 13:12:24 -07:00
// this is the term hash with collection and field name and
// can be looked up directly in indexdb
2014-10-30 13:36:39 -06:00
int64_t m_wordId ;
int64_t m_phraseId;
2013-08-02 13:12:24 -07:00
// hash of field name then collection, used to hash termId
2014-10-30 13:36:39 -06:00
int64_t m_prefixHash;
2014-11-10 14:45:11 -08:00
int32_t m_posNum;
2013-08-02 13:12:24 -07:00
// are we in a phrase in a wikipedia title?
2014-11-10 14:45:11 -08:00
int32_t m_wikiPhraseId;
2013-08-02 13:12:24 -07:00
// . this is just the hash of m_term and is used for highlighting, etc.
// . it is 0 for terms in a field?
2014-10-30 13:36:39 -06:00
int64_t m_rawWordId ;
int64_t m_rawPhraseId ;
2016-03-01 16:42:49 +01:00
2013-08-02 13:12:24 -07:00
// the field as a convenient numeric code
field_code_t m_fieldCode;
2013-08-02 13:12:24 -07:00
// . '-' means to exclude from search results
// . '+' means to include in all search results
// . if we're a phrase term, signs distribute across quotes
char m_wordSign;
char m_phraseSign;
// this is 1 if the associated word is a valid query term but its
// m_explicitBit is 0. we use this to save explicit bits for those
// terms that need them (like those terms in complicated nested boolean
// expressions) and just use a hardCount to see how many hard required
// terms are contained by a document. see IndexTable.cpp "hardCount"
char m_hardCount;
// the parenthetical level of this word in the boolean expression.
// level 0 is the first level.
char m_level;
// is this word a query stop word?
bool m_isQueryStopWord ;
// is it a plain stop word?
bool m_isStopWord ;
bool m_isPunct;
// are we an op code?
char m_opcode;
// . the ignore code
// . explains why this query term should be ignored
// . see IGNORE_* enums above
ignore_reason_t m_ignoreWord;
ignore_reason_t m_ignorePhrase;
// so we ignore gbsortby:offerprice in bool expressions
bool m_ignoreWordInBoolQuery;
2013-08-02 13:12:24 -07:00
// is this query single word in quotes?
bool m_inQuotes ;
// is this word in a phrase that is quoted?
bool m_inQuotedPhrase;
// what word # does the quote we are in start at?
2014-11-10 14:45:11 -08:00
int32_t m_quoteStart;
int32_t m_quoteEnd; // inclusive!
2013-08-02 13:12:24 -07:00
// are we connected to the alnum word on our left/right?
bool m_leftConnected;
bool m_rightConnected;
// if we're in middle or right end of a phrase, where does it start?
2014-11-10 14:45:11 -08:00
int32_t m_leftPhraseStart;
2013-08-02 13:12:24 -07:00
// . what QueryTerm does our "phrase" map to? NULL if none.
// . this allows us to OR in extra bits into that QueryTerm's m_bits
// member that correspond to the single word constituents
// . remember, m_bits is a bit vector that represents the QueryTerms
// a document contains
class QueryTerm *m_queryPhraseTerm;
// . what QueryTerm does our "word" map to? NULL if none.
// . used by QueryBoolean since it uses QueryWords heavily
class QueryTerm *m_queryWordTerm;
2016-03-01 16:42:49 +01:00
// user defined weights
int32_t m_userWeightForWord;
float m_userWeightForPhrase;
2013-08-02 13:12:24 -07:00
bool m_queryOp;
// is this query word before a | (pipe) operator?
bool m_piped;
2014-02-03 19:17:58 -08:00
// for min/max score ranges like gbmin:price:1.99
float m_float;
2016-03-01 16:42:49 +01:00
// for gbminint:99 etc. uses integers instead of floats for better res
2014-11-10 14:45:11 -08:00
int32_t m_int;
// for holding some synonyms
SafeBuf m_synWordBuf;
2014-03-18 10:44:56 -07:00
// when an operand is an expression...
class Expression *m_expressionPtr;
2013-08-02 13:12:24 -07:00
};
// . we filter the QueryWords and turn them into QueryTerms
// . QueryTerms are the important parts of the QueryWords
class QueryTerm {
public:
void constructor ( ) ;
2013-08-02 13:12:24 -07:00
// the query word we were derived from
2017-02-20 15:12:17 +01:00
const QueryWord *m_qword;
2016-03-01 16:42:49 +01:00
2013-08-02 13:12:24 -07:00
// . are we a phrase termid or single word termid from that QueryWord?
// . the QueryWord instance represents both, so we must choose
bool m_isPhrase;
2016-03-01 16:42:49 +01:00
2013-08-02 13:12:24 -07:00
// this is phraseId for phrases, and wordId for words
2014-10-30 13:36:39 -06:00
int64_t m_termId;
2016-03-01 16:42:49 +01:00
2013-08-02 13:12:24 -07:00
// used by Matches.cpp
2014-10-30 13:36:39 -06:00
int64_t m_rawTermId;
2013-08-02 13:12:24 -07:00
// sign of the phrase or word we used
char m_termSign;
2016-03-01 16:42:49 +01:00
2013-08-02 13:12:24 -07:00
// our representative bit (up to 16 MAX_QUERY_TERMS)
qvec_t m_explicitBit;
2016-02-25 22:41:33 +01:00
2013-08-02 13:12:24 -07:00
// usually this equal m_explicitBit, BUT if a word is repeated
// in different areas of the doc, we union all the individual
// explicit bits of that repeated word into this bit vec. it is
// used by Matches.cpp only so far.
qvec_t m_matchesExplicitBits;
2016-02-25 22:41:33 +01:00
2013-08-02 13:12:24 -07:00
// this is 1 if the associated word is a valid query term but its
// m_explicitBit is 0. we use this to save explicit bits for those
// terms that need them (like those terms in complicated nested boolean
// expressions) and just use a hardCount to see how many hard required
// terms are contained by a document. see IndexTable.cpp "hardCount"
char m_hardCount;
2014-03-19 13:51:32 -07:00
// the "number" of the query term used for evaluation boolean
2014-03-20 10:03:25 -07:00
// expressions in Expression::isTruth(). Basically just the
// QueryTermInfo for which this query term belongs. each QueryTermInfo
2014-03-20 10:03:25 -07:00
// is like a single query term and all its synonyms, etc.
2014-11-10 14:45:11 -08:00
int32_t m_bitNum;
2014-03-19 13:51:32 -07:00
2013-08-02 13:12:24 -07:00
// point to term, either m_word or m_phrase
char *m_term;
2014-11-10 14:45:11 -08:00
int32_t m_termLen;
2016-02-25 22:41:33 +01:00
2013-08-02 13:12:24 -07:00
// point to the posdblist that represents us
class RdbList *m_posdbListPtr;
// languages query term is in. currently this is only valid for
// synonyms of other query terms. so we can show what language the
// synonym is for in the xml/json feed.
uint64_t m_langIdBits;
bool m_langIdBitsValid;
int64_t m_termFreq;
float m_termFreqWeight;
2013-08-02 13:12:24 -07:00
// . our representative bits
// . the bits in this bit vector is 1-1 with the QueryTerms
// . if a doc has query term #i then bit #i will be set
// . if a doc EXplicitly has phrase "A B" then it may have
// term A and term B implicity
// . therefore we also OR the bits for term A and B into m_implicitBits
// . THIS SHIT SHOULD be just used in setBitScores() !!!
qvec_t m_implicitBits;
2016-03-01 16:42:49 +01:00
2013-08-02 13:12:24 -07:00
// Summary.cpp and Matches.cpp use this one
bool m_isQueryStopWord ;
2016-03-01 16:42:49 +01:00
2013-08-02 13:12:24 -07:00
// IndexTable.cpp uses this one
bool m_inQuotes;
2016-03-01 16:42:49 +01:00
2013-08-02 13:12:24 -07:00
// user defined weight for this term, be it phrase or word
2014-11-17 14:46:31 -08:00
float m_userWeight;
2016-03-01 16:42:49 +01:00
2013-08-02 13:12:24 -07:00
// . is this query term before a | (pipe) operator?
2017-05-30 15:31:32 +02:00
// . if so we must read the whole termlist
2013-08-02 13:12:24 -07:00
bool m_piped;
2016-03-01 16:42:49 +01:00
2013-08-02 13:12:24 -07:00
// . we ignore component terms unless their compound term is not cached
// . now this is used to ignore low tf synonym terms only
bool m_ignored ;
2016-03-01 16:42:49 +01:00
2013-08-02 13:12:24 -07:00
// . if synonymOf is not NULL, then m_term points into m_synBuf, not
// m_buf
2017-05-22 16:46:18 +02:00
const QueryTerm *m_synonymOf;
2014-10-30 13:36:39 -06:00
int64_t m_synWids0;
int64_t m_synWids1;
2014-11-10 14:45:11 -08:00
int32_t m_numAlnumWordsInSynonym;
2016-03-01 16:42:49 +01:00
2013-08-02 13:12:24 -07:00
// like if we are the "nj" syn of "new jersey", this will be 2 words
// since "new jersey", our base, is 2 alnum words.
2014-11-10 14:45:11 -08:00
int32_t m_numAlnumWordsInBase;
2016-03-01 16:42:49 +01:00
2013-08-02 13:12:24 -07:00
// copied from derived QueryWord
field_code_t m_fieldCode;
2016-09-19 12:32:26 +02:00
bool isSplit() const;
2013-08-02 13:12:24 -07:00
bool m_isRequired;
2016-03-01 16:42:49 +01:00
bool m_isWikiHalfStopBigram;
2016-03-01 16:42:49 +01:00
2013-08-02 13:12:24 -07:00
// if a single word term, what are the term #'s of the 2 phrases
// we can be in? uses -1 to indicate none.
2014-11-10 14:45:11 -08:00
int32_t m_leftPhraseTermNum;
int32_t m_rightPhraseTermNum;
2016-03-01 16:42:49 +01:00
2013-08-02 13:12:24 -07:00
// same as above basically
2017-05-22 16:46:18 +02:00
const QueryTerm *m_leftPhraseTerm;
const QueryTerm *m_rightPhraseTerm;
2015-01-15 12:12:25 -08:00
2013-08-02 13:12:24 -07:00
char m_startKey[MAX_KEY_BYTES];
char m_endKey [MAX_KEY_BYTES];
char m_ks;
};
2014-06-10 19:32:46 -07:00
#define MAX_EXPRESSIONS 100
2014-03-18 10:44:56 -07:00
// operand1 AND operand2 OR ...
// operand1 OR operand2 AND ...
class Expression {
public:
2014-11-10 14:45:11 -08:00
bool addExpression (int32_t start,
int32_t end,
2016-09-19 12:32:26 +02:00
Query *q,
2014-11-10 14:45:11 -08:00
int32_t level );
2016-09-19 12:32:26 +02:00
bool isTruth(const unsigned char *bitVec, int32_t vecSize) const;
2014-03-18 10:44:56 -07:00
// . what QueryTerms are UNDER the influence of the NOT opcode?
// . we read in the WHOLE termlist of those that are (like '-' sign)
// . returned bit vector is 1-1 with m_qterms in Query class
2016-02-25 22:41:33 +01:00
2014-11-10 14:45:11 -08:00
int32_t m_expressionStartWord;
int32_t m_numWordsInExpression;
2016-09-19 12:32:26 +02:00
const Query *m_q;
2014-03-18 10:44:56 -07:00
};
2013-08-02 13:12:24 -07:00
// . this is the main class for representing a query
// . it contains array of QueryWords (m_qwords[]) and QueryTerms (m_qterms[])
class Query {
public:
void reset();
Query();
~Query();
void constructor();
void destructor();
// . returns false and sets g_errno on error
// . after calling this you can call functions below
2016-02-25 16:02:15 +01:00
bool set2 ( const char *query ,
2013-08-02 13:12:24 -07:00
uint8_t langId ,
bool queryExpansion ,
bool useQueryStopWords,
int32_t maxQueryTerms = 0x7fffffff );
2013-08-02 13:12:24 -07:00
const char *getQuery() const { return m_originalQuery.getBufStart(); }
int32_t getQueryLen() const { return m_originalQuery.length(); }
2016-09-19 12:20:26 +02:00
int32_t getNumTerms() const { return m_numTerms; }
char getTermSign(int32_t i) const { return m_qterms[i].m_termSign; }
bool isPhrase(int32_t i) const { return m_qterms[i].m_isPhrase; }
int64_t getTermId(int32_t i) const { return m_qterms[i].m_termId; }
int64_t getRawTermId (int32_t i) const { return m_qterms[i].m_rawTermId; }
const char *getTerm(int32_t i) const { return m_qterms[i].m_term; }
int32_t getTermLen(int32_t i) const { return m_qterms[i].m_termLen; }
bool isSplit() const;
2013-08-02 13:12:24 -07:00
// the new way as of 3/12/2014. just determine if matches the bool
// query or not. let's try to offload the scoring logic to other places
// if possible.
2014-03-13 13:09:33 -07:00
// bitVec is all the QueryWord::m_opBits some docid contains, so
// does it match our boolean query or not?
2016-09-19 12:32:26 +02:00
bool matchesBoolQuery(const unsigned char *bitVec, int32_t vecSize) const;
2013-08-02 13:12:24 -07:00
// modify query terms based on patters and rule-of-thumb. Eg "example.com" is probably a search
// for a domain and "file.open()" is probably for an API/SDK
2017-07-07 14:19:45 +02:00
void modifyQuery(ScoringWeights *scoringWeights, bool modifyDomainLikeSearches, bool modifyAPILikeSearches);
private:
2013-08-02 13:12:24 -07:00
// sets m_qwords[] array, this function is the heart of the class
bool setQWords ( char boolFlag , bool keepAllSingles ,
class Words &words , class Phrases &phrases ) ;
// sets m_qterms[] array from the m_qwords[] array
2017-02-13 11:37:10 +01:00
bool setQTerms ( const class Words &words ) ;
2013-08-02 13:12:24 -07:00
// helper funcs for parsing query into m_qwords[]
2016-09-19 12:32:26 +02:00
bool isConnection(const char *s, int32_t len) const;
2013-08-02 13:12:24 -07:00
2016-03-14 12:18:08 +01:00
void dumpToLog() const;
public:
const char *originalQuery() const { return m_originalQuery.getBufStart(); }
2017-02-15 22:18:18 +01:00
2013-08-02 13:12:24 -07:00
// hash of all the query terms
2016-09-19 12:32:26 +02:00
int64_t getQueryHash() const;
2013-08-02 13:12:24 -07:00
// return -1 if does not exist in query, otherwise return the
// query word num
2016-09-19 12:32:26 +02:00
int32_t getWordNum(int64_t wordId) const;
2013-08-02 13:12:24 -07:00
2017-02-15 22:39:06 +01:00
private:
2013-08-02 13:12:24 -07:00
// . bit vector that is 1-1 with m_qterms[]
// . only has bits that we must have if we were default AND
qvec_t m_requiredBits;
qvec_t m_matchRequiredBits;
qvec_t m_negativeBits;
qvec_t m_forcedBits;
// bit vector for terms that are synonyms
qvec_t m_synonymBits;
2014-11-10 14:45:11 -08:00
int32_t m_numRequired;
2013-08-02 13:12:24 -07:00
2017-02-15 22:39:06 +01:00
public:
2013-08-02 13:12:24 -07:00
// language of the query
uint8_t m_langId;
bool m_useQueryStopWords;
private:
2017-02-13 16:59:55 +01:00
// use a generic buffer for m_qwords to point into
2013-08-02 13:12:24 -07:00
// so we don't have to malloc for them
SmallBuf<GBUF_SIZE> m_queryWordBuf;
2013-08-02 13:12:24 -07:00
public:
2016-02-25 22:41:33 +01:00
QueryWord *m_qwords;
2014-11-10 14:45:11 -08:00
int32_t m_numWords;
2013-08-02 13:12:24 -07:00
// QueryWords are converted to QueryTerms
2014-11-10 14:45:11 -08:00
int32_t m_numTerms;
2013-08-02 13:12:24 -07:00
int32_t m_numTermsUntruncated;
2017-02-15 22:19:52 +01:00
private:
SafeBuf m_queryTermBuf;
2017-02-15 22:19:52 +01:00
public:
QueryTerm *m_qterms ;
2013-08-02 13:12:24 -07:00
// site: field will disable site clustering
// ip: field will disable ip clustering
bool m_hasPositiveSiteField;
bool m_hasIpField;
bool m_hasUrlField;
bool m_hasSubUrlField;
// . we set this to true if it is a boolean query
// . when calling Query::set() above you can tell it explicitly
// if query is boolean or not, OR you can tell it to auto-detect
// by giving different values to the "boolFlag" parameter.
bool m_isBoolean;
// if they got a gbdocid: in the query and it's not boolean, set these
2014-10-30 13:36:39 -06:00
int64_t m_docIdRestriction;
2013-08-02 13:12:24 -07:00
2017-02-15 22:19:52 +01:00
private:
2015-07-13 14:59:44 -06:00
// for holding the filtered query, in utf8
SmallBuf<128> m_filteredQuery;
2013-08-02 13:12:24 -07:00
SmallBuf<128> m_originalQuery;
2017-02-15 22:18:18 +01:00
public:
2013-08-02 13:12:24 -07:00
// . we now contain the parsing components for boolean queries
2014-03-18 10:44:56 -07:00
Expression m_expressions[MAX_EXPRESSIONS];
2014-11-10 14:45:11 -08:00
int32_t m_numExpressions;
2013-08-02 13:12:24 -07:00
2014-11-10 14:45:11 -08:00
int32_t m_maxQueryTerms ;
2013-08-02 13:12:24 -07:00
bool m_queryExpansion;
bool m_truncated;
};
2016-03-08 22:14:30 +01:00
#endif // GB_QUERY_H