public class Query
extends java.lang.Object
| Constructor and Description |
|---|
Query() |
| Modifier and Type | Method and Description |
|---|---|
Query |
addBias(java.lang.String name,
java.lang.String content,
Bias.Strength strength)
|
Query |
addCustomUrlParam(CustomUrlParam customUrlParam)
Sets any additional parameters that can be used to trigger rules. |
Query |
addCustomUrlParam(java.lang.String key,
java.lang.String value)
Sets any additional parameters that can be used to trigger rules. |
Query |
addCustomUrlParamsByString(java.lang.String values)
Helper method that takes a ~ separated string of additional parameters that can be
used to trigger rules. |
Query |
addExcludedNavigations(java.lang.String... navigationName)
Specify which navigations should not be returned. |
protected Query |
addField(java.util.List<java.lang.String> fields,
java.lang.String... name) |
Query |
addFields(java.lang.String... name)
Specify which fields should be returned on each record that comes back from the engine. |
Query |
addIncludedNavigations(java.lang.String... navigationName)
Specify which navigations should be returned. |
Query |
addOrField(java.lang.String... name)
Specify which fields should be queried with 'OR' instead of the default 'AND'. |
Query |
addQueryUrlParams(java.lang.String key)
|
Query |
addQueryUrlParams(java.lang.String key,
java.lang.String value)
|
Query |
addRangeRefinement(java.lang.String navigationName,
java.lang.String low,
java.lang.String high)
Add a range refinement. |
Query |
addRangeRefinement(java.lang.String navigationName,
java.lang.String low,
java.lang.String high,
boolean exclude)
Add a range refinement. |
Query |
addRefinementsByString(java.lang.String refinementString)
A helper method to parse and set refinements. |
Query |
addValueRefinement(java.lang.String navigationName,
java.lang.String value)
Add a value refinement. |
Query |
addValueRefinement(java.lang.String navigationName,
java.lang.String value,
boolean exclude)
Add a value refinement. |
protected static Biasing |
convertBiasing(Biasing biasing) |
protected static MatchStrategy |
convertPartialMatchStrategy(MatchStrategy strategy) |
protected static Sort |
convertSort(Sort sort) |
java.lang.String |
getArea() |
Biasing |
getBiasing() |
java.lang.String |
getBiasingProfile() |
java.lang.String |
getBridgeJson(java.lang.String clientKey)
Used internally by the bridge object to generate the JSON that is sent to the search service. |
protected java.lang.String |
getBridgeJsonRefinementSearch(java.lang.String clientKey) |
java.lang.String |
getBridgeRefinementsJson(java.lang.String clientKey,
java.lang.String navigationName)
Used internally by the bridge object to generate the JSON that is sent to the search service. |
java.lang.String |
getCollection() |
java.util.List<CustomUrlParam> |
getCustomUrlParams() |
java.lang.String |
getCustomUrlParamsString() |
java.util.List<java.lang.String> |
getExcludeNavigations() |
java.util.List<java.lang.String> |
getFields() |
java.util.List<java.lang.String> |
getIncludeNavigations() |
java.lang.String |
getLanguage() |
MatchStrategy |
getMatchStrategy() |
java.lang.String |
getMatchStrategyName() |
java.util.Map<java.lang.String,Navigation> |
getNavigations() |
java.util.List<java.lang.String> |
getOrFields() |
int |
getPageSize() |
java.lang.String |
getQuery() |
java.util.Map<java.lang.String,java.lang.String> |
getQueryUrlParams() |
java.lang.String |
getRefinementString() |
java.lang.String |
getSessionId() |
int |
getSkip() |
java.util.List<Sort> |
getSort() |
java.lang.String |
getSubCollection()
Deprecated.
since 2.0, use getCollection instead.
|
java.lang.String |
getVisitorId() |
boolean |
isAutocorrectionDisabled() |
boolean |
isPruneRefinements() |
boolean |
isReturnBinary() |
boolean |
isWildcardSearchEnabled() |
Query |
setArea(java.lang.String area)
The area you wish to fire against, production, staging, etc... |
Query |
setBiasing(Biasing biasing)
Add a biasing profile, which is defined at query time. |
Query |
setBiasingAugment(boolean augment)
|
Query |
setBiasingProfile(java.lang.String biasingProfile)
Override the biasing profile used for this query - takes precedence over any
biasing profile set in the command center. |
Query |
setBringToTop(java.lang.String... bringToTop)
|
Query |
setCollection(java.lang.String collection)
The collection to use. |
Query |
setDisableAutocorrection(boolean disableAutocorrection)
Specifies whether the auto-correction behavior should be disabled. |
Query |
setInfluence(java.lang.Float influence)
|
Query |
setLanguage(java.lang.String language)
Sets the language filter on the query and restricts the results to a certain language. |
Query |
setMatchStrategy(MatchStrategy matchStrategy)
A match strategy allows you to explicitly manage recall on a per query basis. |
Query |
setMatchStrategyName(java.lang.String matchStrategyName)
Override the match strategy used for this query - takes precedence over any
match strategy set in the command center. |
Query |
setPageSize(int pageSize)
Page size. |
Query |
setPruneRefinements(boolean pruneRefinements)
Specifies whether refinements should be pruned from
the available navigation. |
Query |
setQuery(java.lang.String query)
Set a search string. |
Query |
setQueryUrlParams(java.util.Map<java.lang.String,java.lang.String> queryUrlParams)
Sets the query level url parameters. |
Query |
setRestrictNavigation(RestrictNavigation restrictNavigation)
Warning This will count as two queries against your search index. |
Query |
setRestrictNavigation(java.lang.String name,
int count)
Warning @see Query#setRestrictNavigation(RestrictNavigation). |
Query |
setReturnBinary(boolean returnBinary)
Tells the search service to return binary data. |
Query |
setSessionId(java.lang.String sessionId)
A unique string identifier of the session that your customer is currently in. |
Query |
setSkip(int skip)
Tell the search service to offset by N records. |
Query |
setSort(Sort... sort)
Specifies the sort order applied to the fields in the order specified. |
Query |
setSubCollection(java.lang.String subCollection)
Deprecated.
since 2.0, use setCollection instead.
|
Query |
setVisitorId(java.lang.String visitorId)
A unique string identifier of an end customer. |
Query |
setWildcardSearchEnabled(boolean wildcardSearchEnabled)
Indicate if the *(star) character in the search string should be treated as a wildcard prefix search. |
protected java.lang.String[] |
splitRefinements(java.lang.String refinementString) |
public java.lang.String getBridgeJson(java.lang.String clientKey)
Used internally by the bridge object to generate the JSON that is sent to the search service.
clientKey - The client key used to authenticate this request.public java.util.List<CustomUrlParam> getCustomUrlParams()
public boolean isWildcardSearchEnabled()
protected static MatchStrategy convertPartialMatchStrategy(MatchStrategy strategy)
public Query setWildcardSearchEnabled(boolean wildcardSearchEnabled)
Indicate if the *(star) character in the search string should be treated as a wildcard prefix search.
For example, `sta*` will match `star` and `start`.
JSON Reference:
{ "wildcardSearchEnabled" : true }
wildcardSearchEnabled - true to enable wildcard search, false otherwise.public java.lang.String getBridgeRefinementsJson(java.lang.String clientKey,
java.lang.String navigationName)
Used internally by the bridge object to generate the JSON that is sent to the search service.
clientKey - The client key used to authenticate this request.public java.lang.String getQuery()
public Query setQuery(java.lang.String query)
Set a search string. If query is blank all records are considered. There are some limits enforced on the search string, it:
- must not exceed 50 characters
- must not exceed 10 terms.
If the limits are exceeded, the search string is truncated until all limits are satisfied. For example, the following search string
The quick brown fox jumps over the high bridge into the cold river.
will get truncated to:
The quick brown fox jumps over the high bridge
The terms `the`, `cold`, and `river` were truncated because the term limit was exceed, and `into` was also removed because the
resulting string exceeded the character limit. Stop words are included in the string when determining if limits are exceeded. If
there is only one term and it exceeds the character limit, the query will fail.
JSON Reference:
{ "query": "gloves" }
query - The search string to fire against the engine.public java.lang.String getSubCollection()
public Query setSubCollection(java.lang.String subCollection)
subCollection - The string representation of a collection query.public java.lang.String getCollection()
public Query setCollection(java.lang.String collection)
The collection to use. If you have uploaded additional data into collections apart from the default
collection using the stream tool, you can access them by specifying them here.
You can also search across multiple collections. It is important to note that relevancy is affected across
collections and it is recommended that collections be modeled so that cross-collection searching is not required.
As an example, to search across FAQs and Manuals you would use "FAQs|Manuals".
JSON Reference:
{ "collection": "FAQs" }
{ "collection": "FAQs|Manuals" }
collection - The string representation of a collection query.public java.lang.String getArea()
public Query setArea(java.lang.String area)
The area you wish to fire against, production, staging, etc...
If blank, the default production area will be used.
JSON Reference:
{ "area": "Development" }
area - The area name.public java.lang.String getRefinementString()
public java.lang.String getCustomUrlParamsString()
protected java.lang.String getBridgeJsonRefinementSearch(java.lang.String clientKey)
clientKey - Your client keypublic Query addRefinementsByString(java.lang.String refinementString)
A helper method to parse and set refinements.
If you pass in refinements of the format
Brand=Bose~price:20..80
The query object will correctly parse out the refinements.
refinementString - A tilde separated list of refinementsprotected java.lang.String[] splitRefinements(java.lang.String refinementString)
public Query addCustomUrlParam(CustomUrlParam customUrlParam)
Sets any additional parameters that can be used to trigger rules.
Takes a CustomUrlParam object.
customUrlParam - The parameter to addpublic Query addCustomUrlParam(java.lang.String key, java.lang.String value)
Sets any additional parameters that can be used to trigger rules.
Takes a name and a value.
JSON Reference:
Custom URL parameters separated by ~ in the form:
{ "customUrlParams": [ { "key": "region", "value": "east" } ] }
key - The parameter keyvalue - The parameter valuepublic Query addCustomUrlParamsByString(java.lang.String values)
Helper method that takes a ~ separated string of additional parameters that can be
used to trigger rules. Takes ~ separated name/value list
values - The list of name/valuespublic java.util.List<java.lang.String> getFields()
public Query addFields(java.lang.String... name)
Specify which fields should be returned on each record that comes back from the engine. You may specify more
than one field, if you specify \\* all fields will be returned.
If this parameter is blank the search service will return no attributes with the records.
JSON Reference:
{ "fields": [ "width", "brand", "height" ] }
name - The case-sensitive name of the attribute to returnprotected Query addField(java.util.List<java.lang.String> fields, java.lang.String... name)
public java.util.List<java.lang.String> getOrFields()
public Query addOrField(java.lang.String... name)
Specify which fields should be queried with 'OR' instead of the default 'AND'.
This behavior is typically defined in command center on a per navigation basis. However,
you can set which fields should be treated as an OR field at the query level if desired.
As with normal refinement selections, once you have refined, the list of refinements for
that selected navigation will no longer be returned.
JSON Reference:
{ "orFields": [ "field1", "field2" ] }
name - The field that should be treated as OR by the search service before
being executed.public Query addRangeRefinement(java.lang.String navigationName, java.lang.String low, java.lang.String high)
Add a range refinement. Takes a refinement name, a lower and upper bounds.
navigationName - The name of the refinementlow - The low valuehigh - The high valuepublic Query addRangeRefinement(java.lang.String navigationName, java.lang.String low, java.lang.String high, boolean exclude)
Add a range refinement. Takes a refinement name, a lower and upper bounds, and whether or not to exclude
this refinement.
navigationName - The name of the refinementlow - The low valuehigh - The high valueexclude - True if the results should exclude this range refinement, false otherwisepublic Query addValueRefinement(java.lang.String navigationName, java.lang.String value)
Add a value refinement. Takes a refinement name and a value.
navigationName - The name of the navigationvalue - The refinement valuepublic Query addValueRefinement(java.lang.String navigationName, java.lang.String value, boolean exclude)
Add a value refinement. Takes a refinement name, a value, and whether or not to exclude this refinement.
navigationName - The name of the navigationvalue - The refinement valueexclude - True if the results should exclude this value refinement, false otherwisepublic int getSkip()
public Query setSkip(int skip)
Tell the search service to offset by N records. For example, if N is 10, the records returned will start at 11.
JSON Reference:
{ "skip": 400 }
skip - The number of documents to skippublic int getPageSize()
public Query setPageSize(int pageSize)
Page size. Default is 10.
JSON Reference:
{ "pageSize": 8 }
pageSize - The number of records to return with the query.public java.util.Map<java.lang.String,Navigation> getNavigations()
public boolean isReturnBinary()
public Query setReturnBinary(boolean returnBinary)
Tells the search service to return binary data. This is enabled by default in the APIs for more efficient transport.
To disable this in an API, set this to `false`.
JSON Reference:
If passed true, informs the search service to return binary data rather than JSON.
{ "returnBinary": true }
returnBinary - Whether to tell the search service to return binary data rather than JSON.public java.lang.String getBiasingProfile()
public Query setBiasingProfile(java.lang.String biasingProfile)
Override the biasing profile used for this query - takes precedence over any
biasing profile set in the command center.
JSON Reference:
{ "biasingProfile": "PopularityBias" }
biasingProfile - The name of the biasing profilepublic java.lang.String getMatchStrategyName()
public Query setMatchStrategyName(java.lang.String matchStrategyName)
Override the match strategy used for this query - takes precedence over any
match strategy set in the command center.
JSON Reference:
{ "matchStrategyName": "RelaxedMatch" }
matchStrategyName - The name of the match strategypublic java.lang.String getLanguage()
public Query setLanguage(java.lang.String language)
Sets the language filter on the query and restricts the results to a certain language. If you do not specify a
language, english ("lang_en") will be considered the default. An unrecognized language will result in an error.
Currently supported languages are:
lang_en
JSON Reference:
{ "language": "lang_en" }
language - The value for language restrictpublic boolean isPruneRefinements()
public Query setPruneRefinements(boolean pruneRefinements)
Specifies whether refinements should be pruned from
the available navigation.
A refinement is pruned if the number of results for that refinement is zero.
If all refinements from a navigation are pruned, that
navigation is also pruned.
Defaults to true
JSON Reference:
{ pruneRefinements: false }
pruneRefinements - true to prune refinements, false otherpublic boolean isAutocorrectionDisabled()
public Query setDisableAutocorrection(boolean disableAutocorrection)
Specifies whether the auto-correction behavior should be disabled. By default, when no results are returned
for the given query (and there is a did-you-mean available), the first did-you-mean is automatically queried
instead.
Defaults to false
JSON Reference:
{ "disableAutocorrection": false }
disableAutocorrection - true to disable autocorrection, false otherwisepublic Query setRestrictNavigation(RestrictNavigation restrictNavigation)
Warning This will count as two queries against your search index.
Typically, this feature is used when you have a large number of navigation items that will overwhelm the end
user. It works by using one of the existing navigation items to decide what the query is about and fires a second
query to restrict the navigation to the most relevant set of navigation items for this search term.
For example, if you pass in a search of `paper` and a restrict navigation of `category:2`
The bridge will find the category navigation refinements in the first query and fire a second query for the top 2
most populous categories. Therefore, a search for something generic like "paper" will bring back top category
matches like copy paper (1,030), paper pads (567). The bridge will fire off the second query with the search
term, plus an OR refinement with the most likely categories. The navigation items in the first query are
entirely replaced with the navigation items in the second query, except for the navigation that was used for the
restriction so that users still have the ability to navigate by all category types.
JSON Reference:
{ "restrictNavigation": { "name": "category", "count": 2 } }
restrictNavigation - Restriction criteriapublic Query setRestrictNavigation(java.lang.String name, int count)
Warning @see Query#setRestrictNavigation(RestrictNavigation). This is a convenience method.
name - the name of the field should be used in the navigation restriction in the second query.count - the number of fields matchespublic java.util.List<Sort> getSort()
public Query setSort(Sort... sort)
Specifies the sort order applied to the fields in the order specified. If no sort criteria are specified, the
default is to sort by relevance. There is a special sort field `_relevance`, which also specifies sorting by
relevance. It is possible to specify multiple sort criteria. The criteria order matters, as the records will be
sorted by the first criteria and then any matches will be tie-broken using the next criteria. Given an example
where the sort is specified as `category` then `_relevance`, results will be sorted first by `category` and
relevance will only affect the order between records that have the same category.
Please note, sorting is based on the actual value in the record. For example, if sorting on `price`, and
`price` is a `Range` navigation, the records will be sorted according to the actual price value in the record
and not the bucket value.
The order field can be set to either `Ascending` or `Descending`. When sorting by relevance, the order is always
`Descending`. For any other field, the default order is `Ascending`.
JSON Reference:
{ "sort": { "field": "price", "order": "Descending" } }
{ "sort": [{ "field": "_relevance" }, { "field": "price", "order": "Descending" }] }
{ "sort": [{ "field": "brand", "order":"Ascending" }, { "field": "_relevance" }, { "field": "price" }] }
sort - Any number of sort criteria.public MatchStrategy getMatchStrategy()
public Query setMatchStrategy(MatchStrategy matchStrategy)
A match strategy allows you to explicitly manage recall on a per query basis. There must always be one term
matching in a query, thus `termsGreaterThan` can only be defined from 1 upwards and `terms` can only be defined
from 2 upwards. It is not possible to match more terms than passed into the query. Relative `mustMatch` values
can be used in conjunction with `termsGreaterThan`. A `"percentage": true` flag denotes a relative `mustMatch`
to the portion of the terms and will always round down (i.e. 50% must match of 3 terms, means that 1 term must
match).
The following is the default match strategy:
```
{ "matchStrategy": { "rules":[{ "terms": 2, "mustMatch": 2 },
{ "terms": 3, "mustMatch": 2 },
{ "terms": 4, "mustMatch": 3 },
{ "terms": 5, "mustMatch": 3 },
{ "terms": 6, "mustMatch": 4 },
{ "terms": 7, "mustMatch": 4 },
{ "terms": 8, "mustMatch": 5 },
{ "termsGreaterThan": 8, "mustMatch": 60, "percentage": true }] } }
```
An exact matching strategy would be:
```
{ "matchStrategy": { "rules": { "termsGreaterThan": 1, "mustMatch": 100, "percentage": true } } }
```
Please note, it is highly recommended that the highest rule is defined with `termsGreaterThan`
and a relative `mustMatch` as that guarantees that the number of matches required grows with the number of terms
passed into the query.
JSON Reference:
{ "matchStrategy": { "rules":[{ "terms": 2, "mustMatch": 2 },
{ "terms": 3, "mustMatch": 2 },
{ "terms": 4, "mustMatch": 3 },
{ "terms": 5, "mustMatch": 3 },
{ "terms": 6, "mustMatch": 4 },
{ "terms": 7, "mustMatch": 4 },
{ "terms": 8, "mustMatch": 5 },
{ "termsGreaterThan": 8, "mustMatch": 60, "percentage": true }] } }
{ "matchStrategy": { "rules": { "termsGreaterThan": 1, "mustMatch": 100, "percentage": true } } }
{ "matchStrategy": { "rules":[{ "terms": 2, "mustMatch": 1 },
{ "termsGreaterThan": 2, "mustMatch": 75, "percentage": true }] } }
matchStrategy - A match strategy composed of partial matching rules.public java.util.List<java.lang.String> getIncludeNavigations()
public Query addIncludedNavigations(java.lang.String... navigationName)
Specify which navigations should be returned. If set, this overrides the navigations defined
in Command Center and only returns the navigations specified. If this parameter is blank the
navigations in Command Center are returned. If a navigation is specified that does not exist,
it will be ignored. The field name supports two types of wildcard characters: '?' and '\*'.
The '?' wildcard will match one character. For example "????_price" will match "sale_price",
but not "sales_price". The '\*' wildcard will match any number of characters. For example, a
name of "\*_price" will match both "sale_price and "sales_price", but not "sale_prices".
JSON Reference:
{ "includedNavigations": [ "width", "brand", "categories.categories.value" ] }
navigationName - The case-sensitive name of the navigation to returnpublic java.util.List<java.lang.String> getExcludeNavigations()
public Query addExcludedNavigations(java.lang.String... navigationName)
Specify which navigations should not be returned. If set, this forces the response to
exclude certain navigations defined in Command Center. If this parameter is blank all
navigations in Command Center are returned. If a navigation name is specified that does
not exist, it will be ignored. If "includedNavigations" are specified, then all
"excludedNavigations" are ignored. Please see the documentation on "includedNavigations"
for details on wildcard characters in the field name.
JSON Reference:
{ "excludedNavigations": [ "width", "brand", "categories.categories.value" ] }
navigationName - The case-sensitive name of the navigation to excludepublic java.util.Map<java.lang.String,java.lang.String> getQueryUrlParams()
public Query setQueryUrlParams(java.util.Map<java.lang.String,java.lang.String> queryUrlParams)
Sets the query level url parameters. These will be used in the future to enable and disable
features, such as disabling Navigations in the response.
queryUrlParams - The map of query level url parameterspublic Query addQueryUrlParams(java.lang.String key)
key - The key of the url parameterThis is a convenience method for when you have no
value for the url parameter.
public Query addQueryUrlParams(java.lang.String key, java.lang.String value)
public Query setBringToTop(java.lang.String... bringToTop)
bringToTop - Any number of product IDs to bring to the top of the result set.This is a convenience method to set which products should be
brought to the top of the result set.
public Query setBiasingAugment(boolean augment)
augment - True to replace the biases defined in Command Center, false to augment.This is a convenience method to set the biasing augment status.
public Query setInfluence(java.lang.Float influence)
influence - The influenceThis is a convenience method to set the biasing influence.
public Query addBias(java.lang.String name, java.lang.String content, Bias.Strength strength)
name - The name of the field to bias oncontent - The value to biasstrength - The strength of the bias. Legal values are: "Absolute_Increase", "Strong_Increase", "Medium_Increase",
"Weak_Increase", "Leave_Unchanged", "Weak_Decrease", "Medium_Decrease", "Strong_Decrease", "Absolute_Decrease".This is a convenience method to add an individual bias.
public java.lang.String getSessionId()
public Query setSessionId(java.lang.String sessionId)
A unique string identifier of the session that your customer is currently in. The sessionID should be a unique value for a
given user that persists for them as long as that user is active on the site for that session. We define a session as the
time that you would consider a duration of an A/B test. In future, A/B testing tools within our solution will leverage
the session ID to group customers into different experiences. Ensuring that session ID is persistent throughout a measure
of time will help ensure that the customer experience is consistent as they shop and browse your site. Therefore, the
sessionID should update only if the user is inactive for some period - we recommend keeping this in alignment for what
you consider a shopping session for your customers. For example, you can align this to the timeout of items stored in the
shopping cart. Session ID should not change when the user logs in and can be used to track a user changing from anonymous
to logged in. Session ID must also be consistent between the Search and Recommendations APIs to ensure correct monitoring of
conversion metrics.
**Important:** Sending raw session IDs is a security risk. Encrypt or hash session IDs prior to transmission.
sessionId - The session IDpublic java.lang.String getVisitorId()
public Query setVisitorId(java.lang.String visitorId)
A unique string identifier of an end customer. Anonymous users (not logged in) should have a visitorID that is
a randomly generated v4 UUID. This visitorID should stay with the anonymous user for as long as possible or
until they log in. When a user logs in, their visitorID change to a known globally unique identifier for that customer.
Visitor ID should remain the same for a particular customer over different sessions. Also, it must be consistent
between the Search and Recommendations APIs to ensure correct monitoring of conversion metrics.
**Important:** Sending raw session IDs is a security risk. Encrypt or hash session IDs prior to transmission.
visitorId - The visitor IDpublic Biasing getBiasing()
public Query setBiasing(Biasing biasing)
Add a biasing profile, which is defined at query time. Possible settings
include:
- `bringToTop`: A list of product IDs to bring to the top of the result set. This list
will ensure that the products are included in the result set and appear in the order
defined.
- `influence`: The influence to apply to query-time biases and biases set in Command Center.
If this field is not defined, then the influence of the biasing profile defined in Command Center will take effect.
If an influence is not defined in Command Center, then the influence will default to 5.
- `augmentBiases`: If true, the biases defined here will augment biasing profiles defined in Command Center.
Otherwise, the biases will override the ones defined in command Center. By default, this is set to false.
- `biases`: A list of biases, which either override or augment biasing profiles defined
in Command Center. See the documentation for `addBias` for more information.
JSON Reference:
{ "biasing": {
"bringToTop": ["productId1","productId3","productId2"]
"influence": 5.0,
"augmentBiases": false,
"biases": [
{"name":"brand", "content":"Brand A", "strength":"Medium_Increase"},
{"name":"brand", "content":"Brand B", "strength":"Strong_Increase"},
{"name":"material", "content":"Material A", "strength":"Strong_Decrease"}
]
}}
biasing - The biasing parametersCopyright © 2013–2016 GroupBy Inc.. All rights reserved.