Load dependencies
querystring
var querystring = require('querystring'),
format = require('./utils/format'),
arrayUtils = require('./utils/array'),
versionUtils = require('./utils/version');
Load dependencies
var querystring = require('querystring'),
format = require('./utils/format'),
arrayUtils = require('./utils/array'),
versionUtils = require('./utils/version');
Expose Query
module.exports = exports = Query;
Create a new Query
function Query(options){
this.solrVersion = (options && options.solrVersion) || undefined;
this.parameters = [];
}
Set a new parameter
Since all possibilities provided by Solr are not available in the Query
object, set()
is there to fit this gap.
Query.prototype.set = function(parameter){
var self = this;
this.parameters.push(parameter);
return self;
};
Set the query parser to use with this request.
Query.prototype.defType = function(type){
var self = this;
var parameter = 'defType=' + type;
this.parameters.push(parameter);
return self;
};
Set the Request Handler used to process the request based on its name
.
Works only if no Request Handler has been configured with /select
as its name in solrconfig.xml.
Query.prototype.requestHandler = Query.prototype.qt = function(name){
var self = this;
var parameter = 'qt=' + name;
this.parameters.push(parameter);
return self;
};
Set the main query
Query.prototype.q = function(q){
var self = this;
var parameter ='q=';
if ( typeof(q) === 'string' ){
parameter += encodeURIComponent(q);
}else{
parameter += querystring.stringify(q, '%20AND%20',':');
}
this.parameters.push(parameter);
return self;
};
Set the default query operator
Query.prototype.qop = function(op){
var self = this;
var parameter ='q.op=';
parameter += op;
this.parameters.push(parameter);
return self;
};
Set the default query field.
Query.prototype.df = function (df) {
var self = this;
var parameter = 'df=';
parameter += df;
this.parameters.push(parameter);
return self;
};
Set the offset where the set of returned documents should begin.
Query.prototype.start = function(start){
var self = this;
var parameter = 'start=' + start ;
this.parameters.push(parameter);
return self;
};
Set the maximum number of documents returned
Query.prototype.rows = function(rows){
var self = this;
var parameter = 'rows=' + rows ;
this.parameters.push(parameter);
return self;
};
Request to use cursorMarks for deep-paging as explained in http://heliosearch.org/solr/paging-and-deep-paging/ Note that usage of a cursor requires a sort containing a uniqueKey field tie breaker
Query.prototype.cursorMark = function(mark){
var self = this;
mark = mark || "*";
var parameter = 'cursorMark=' + mark ;
this.parameters.push(parameter);
return self;
};
Sort a result in descending or ascending order based on one or more fields.
Query.prototype.sort = function(options){
var self = this;
var parameter = 'sort=';
parameter += querystring.stringify(options, ',' , '%20');
this.parameters.push(parameter);
return self;
};
Filter the set of documents found before to return the result with the given range determined by field
, start
and end
.
Query.prototype.rangeFilter = function(options){
var self = this;
options = format.dateISOify(options);
var parameter = 'fq=';
if(Array.isArray(options)){
parameter += "(";
var filters = options.map(function(option){
var key = option.field;
var filter = {};
filter[key] = '[' + encodeURIComponent(option.start) + '%20TO%20' + encodeURIComponent(option.end) + ']';
return format.stringify(filter, '',':');
});
parameter += filters.join('%20AND%20');
parameter += ")";
}else{
var key = options.field;
var filter = {};
filter[key] = '[' + encodeURIComponent(options.start) + '%20TO%20' + encodeURIComponent(options.end) + ']';
parameter += format.stringify(filter, '',':');
}
this.parameters.push(parameter);
return self;
};
Filter the set of documents found before to return the result with the given field
and value
.
Query.prototype.matchFilter = function(field,value){
var self = this;
value = format.dateISOify(value);
var parameter = 'fq=';
parameter += field + ':' + encodeURIComponent(value);
this.parameters.push(parameter);
return self;
};
Specify a set of fields to return.
Query.prototype.fl =
Query.prototype.restrict = function(fields){
var self = this;
var parameter = 'fl=';
if(typeof(fields) === 'string'){
parameter += fields;
}else{
parameter += fields.join(',');
}
this.parameters.push(parameter);
return self;
};
Set the time allowed for a search to finish. Partial results may be returned (if there are any).
Query.prototype.timeout = function(time){
var self = this;
var parameter = 'timeAllowed=' + time;
this.parameters.push(parameter);
return self;
};
Group documents with the given field
Query.prototype.groupBy = function(field){
var self = this;
this.group({
'field': field
});
return self;
};
Group documents using field collapsing or result grouping feature. Field Collapsing collapses a group of results with the same field value down to a single (or fixed number) of entries. Result Grouping groups documents with a common field value into groups, returning the top documents per group, and the top groups based on what documents are in the groups.
Query.prototype.group = function(options){
var self = this;
if(options.on === false){
this.parameters.push('group=false');
}else{
this.parameters.push('group=true');
}
if( options.field ){
options.field = arrayUtils.toArray(options.field);
options.field.forEach(function(field){
self.parameters.push('group.field=' + field);
});
}
if( options.limit !== undefined){
this.parameters.push('group.limit=' + options.limit);
}
if( options.offset !== undefined){
this.parameters.push('group.offset=' + options.offset);
}
if( options.sort ){
this.parameters.push('group.sort=' + encodeURIComponent(options.sort));
}
if( options.format ){
this.parameters.push('group.format=' + encodeURIComponent(options.format));
}
if( options.main !== undefined){
this.parameters.push('group.main=' + options.main);
}
if( options.ngroups !== undefined){
this.parameters.push('group.ngroups=' + options.ngroups);
}
if( options.truncate !== undefined){
this.parameters.push('group.truncate=' + options.truncate);
}
if( options.cache !== undefined){
this.parameters.push('group.cache.percent=' + options.cache);
}
return self;
};
Create a facet
Query.prototype.facet = function(options){
var self = this;
if(options.on === false){
this.parameters.push('facet=false');
}else{
this.parameters.push('facet=true');
}
if(options.query){
this.parameters.push('facet.query=' + encodeURIComponent(options.query))
}
if(options.field){
options.field = arrayUtils.toArray(options.field);
options.field.forEach(function(field) {
self.parameters.push('facet.field=' + field);
});
}
if(options.prefix){
this.parameters.push('facet.prefix=' + encodeURIComponent(options.prefix))
}
if(options.sort){
this.parameters.push('facet.sort=' + encodeURIComponent(options.sort))
}
if(options.limit !== undefined){
this.parameters.push('facet.limit=' + options.limit);
}
if(options.offset !== undefined){
this.parameters.push('facet.offset=' + options.offset);
}
if(options.mincount !== undefined){
this.parameters.push('facet.mincount=' + options.mincount);
}
if(options.missing !== undefined){
this.parameters.push('facet.missing=' + options.missing);
}
if(options.method){
this.parameters.push('facet.method=' + options.method);
}
// Only supported with version 4.0 and above
if(this.solrVersion && (versionUtils.version(this.solrVersion) >= versionUtils.Solr4_0)) {
if(options.pivot){
options.field = arrayUtils.toArray(options.pivot.fields);
options.field.forEach(function(field) {
self.parameters.push('facet.pivot=' + field);
});
}
if(options.pivot.mincount) {
this.parameters.push('facet.pivot.mincount=' + options.pivot.mincount);
}
}
return self;
};
Create a MoreLikeThis. MoreLikeThis constructs a lucene query based on terms within a document.
Query.prototype.mlt = function(options){
var self = this;
if(options.on === false){
this.parameters.push('mlt=false');
}else{
this.parameters.push('mlt=true');
}
if(options.fl){
if(options.fl instanceof Array) options.fl = options.fl.join(',');
this.parameters.push('mlt.fl=' + encodeURIComponent(options.fl))
}
if(options.count !== undefined){
this.parameters.push('mlt.count=' + options.count)
}
if(options.mintf !== undefined){
this.parameters.push('mlt.mintf=' + options.mintf)
}
if(options.mindf !== undefined){
this.parameters.push('mlt.mindf=' + options.mindf);
}
if(options.minwl !== undefined){
this.parameters.push('mlt.minwl=' + options.minwl)
}
if(options.maxwl !== undefined ){
this.parameters.push('mlt.maxwl=' + options.maxwl)
}
if(options.maxqt !== undefined){
this.parameters.push('mlt.maxqt=' + options.maxqt)
}
if(options.maxntp !== undefined){
this.parameters.push('mlt.maxntp=' + options.maxntp);
}
if(options.boost !== undefined){
this.parameters.push('mlt.boost=' + options.boost);
}
if(options.qf){
var parameter = '';
if( typeof options.qf === 'object'){
parameter = querystring.stringify(options.qf, '%20' , '^');;
}else{
parameter = encodeURIComponent(options.qf);
}
this.parameters.push('mlt.qf=' + parameter);
}
return self;
};
Use the DisMax query parser
Query.prototype.dismax = function(){
var self = this;
this.defType('dismax');
return self;
};
Use the EDisMax query parser
Query.prototype.edismax = function(){
var self = this;
this.defType('edismax');
return self;
};
Add the parameter debugQuery. Additional debugging informations will be available in the response.
Query.prototype.debugQuery = function(){
var self = this;
this.parameters.push('debugQuery=true');
return self;
};
//TODO
Query.prototype.ps = function(){};
Set the "boosts" to associate with each fields
Query.prototype.qf = function(options){
var self = this;
var parameter = 'qf=' ;
parameter += querystring.stringify(options, '%20' , '^');
this.parameters.push(parameter);
return self;
};
Set the minimum number or percent of clauses that must match.
Query.prototype.mm = function(minimum){
var self = this;
var parameter = 'mm=' + minimum;
this.parameters.push(parameter);
return self;
};
Set the Phrase Fields parameter. Once the list of matching documents has been identified using the "fq" and "qf" params, the "pf" param can be used to "boost" the score of documents in cases where all of the terms in the "q" param appear in close proximity.
Query.prototype.pf = function(options){
var self = this;
var parameter = 'pf=' ;
parameter += querystring.stringify(options, '%20' , '^');
this.parameters.push(parameter);
return self;
};
Set the phrase slop allowed in a query.
Query.prototype.ps = function(slop){
var self = this;
var parameter = 'ps=' + slop;
this.parameters.push(parameter);
return self;
};
Set the query slop allowed in a query.
Query.prototype.qs = function(slop){
var self = this;
var parameter = 'qs=' + slop;
this.parameters.push(parameter);
return self;
};
Set the tiebreaker in DisjunctionMaxQueries (should be something much less than 1)
Query.prototype.tie = function(tiebreaker){
var self = this;
var parameter = 'tie=' + tiebreaker;
this.parameters.push(parameter);
return self;
};
Set the Boost Query parameter. A raw query string (in the SolrQuerySyntax) that will be included with the user's query to influence the score. If this is a BooleanQuery with a default boost (1.0f) then the individual clauses will be added directly to the main query. Otherwise, the query will be included as is.
Query.prototype.bq = function(options){
var self = this;
var parameter = 'bq=' ;
parameter += querystring.stringify(options, '%20' , '^');
this.parameters.push(parameter);
return self;
};
Set the Functions (with optional boosts) that will be included in the user's query to influence the score.
Query.prototype.bf = function(functions){
var self = this;
var parameter = 'bf=' + functions;
this.parameters.push(parameter);
return self;
};
Set the Functions (with optional boosts) that will be included in the user's query to influence the score.
Query.prototype.boost = function(functions){
var self = this;
var parameter = 'boost=' + encodeURIComponent(functions);
this.parameters.push(parameter);
return self;
};
Build a querystring with the array of this.parameters
.
Query.prototype.build = function(){
return this.parameters.join('&');
};
Set the Query Highlighting parameter.
Query.prototype.hl = function(options){
var self = this;
if(options.on === false){
this.parameters.push('hl=false');
}else{
this.parameters.push('hl=true');
}
if(options.q !== undefined){
if ( typeof(options.q) === 'string' ){
this.parameters.push('hl.q=' + encodeURIComponent(options.q));
}else{
this.parameters.push('hl.q=' + querystring.stringify(options.q, '%20AND%20',':'));
}
}
if(options.qparser !== undefined){
this.parameters.push('hl.qparser=' + encodeURIComponent(options.qparser));
}
if(options.fl !== undefined){
if ( typeof(options.fl) === 'string' ){
this.parameters.push('hl.fl=' + encodeURIComponent(options.fl));
}else{
this.parameters.push('hl.fl=' + options.fl.join(','));
}
}
if(options.snippets !== undefined){
this.parameters.push('hl.snippets=' + encodeURIComponent(options.snippets));
}
if(options.fragsize !== undefined){
this.parameters.push('hl.fragsize=' + encodeURIComponent(options.fragsize));
}
if(options.mergeContiguous !== undefined){
this.parameters.push('hl.mergeContiguous=' + encodeURIComponent(options.mergeContiguous));
}
if(options.requireFieldMatch !== undefined){
this.parameters.push('hl.requireFieldMatch=' + encodeURIComponent(options.requireFieldMatch));
}
if(options.maxAnalyzedChars !== undefined){
this.parameters.push('hl.maxAnalyzedChars=' + encodeURIComponent(options.maxAnalyzedChars));
}
if(options.maxMultiValuedToExamine !== undefined){
this.parameters.push('hl.maxMultiValuedToExamine=' + encodeURIComponent(options.maxMultiValuedToExamine));
}
if(options.maxMultiValuedToMatch !== undefined){
this.parameters.push('hl.maxMultiValuedToMatch=' + encodeURIComponent(options.maxMultiValuedToMatch));
}
if(options.alternateField){
this.parameters.push('hl.alternateField=' + encodeURIComponent(options.alternateField));
}
if(options.maxAlternateFieldLength !== undefined){
this.parameters.push('hl.maxAlternateFieldLength=' + encodeURIComponent(options.maxAlternateFieldLength));
}
if(options.formatter){
this.parameters.push('hl.formatter=' + encodeURIComponent(options.formatter));
}
if(options.simplePre){
this.parameters.push('hl.simple.pre=' + encodeURIComponent(options.simplePre));
}else{
this.parameters.push('hl.simple.pre=<em>');
}
if(options.simplePost){
this.parameters.push('hl.simple.post=' + encodeURIComponent(options.simplePost));
}else{
this.parameters.push('hl.simple.post=<%2Fem>');
}
if(options.fragmenter){
this.parameters.push('hl.fragmenter=' + encodeURIComponent(options.fragmenter));
}
if(options.highlightMultiTerm !== undefined){
this.parameters.push('hl.highlightMultiTerm=' + encodeURIComponent(options.highlightMultiTerm));
}
if(options.usePhraseHighlighter !== undefined){
this.parameters.push('hl.usePhraseHighlighter=' + encodeURIComponent(options.usePhraseHighlighter));
}
if(options.regexSlop !== undefined){
this.parameters.push('hl.regex.slop=' + encodeURIComponent(options.regexSlop));
}
if(options.regexPattern){
this.parameters.push('hl.regex.pattern=' + encodeURIComponent(options.regexPattern));
}
if(options.regexMaxAnalyzedChars){
this.parameters.push('hl.regex.maxAnalyzedChars=' + encodeURIComponent(options.regexMaxAnalyzedChars));
}
if(options.preserveMulti !== undefined){
this.parameters.push('hl.preserveMulti=' + encodeURIComponent(options.preserveMulti));
}
if(options.payloads !== undefined){
this.parameters.push('hl.payloads=' + encodeURIComponent(options.payloads));
}
return self;
};