Leading practices for improving search response time
Leading practices for improving search response time
The search response time is the time your Coveo organization takes to provide results when a user sends a query.
Some factors may imperceptibly or noticeably increase this response time. End users, administrators, or developers can leverage Coveo features that create more complex queries, which then require more resources and therefore notably or significantly increases the search response time. Complex queries can be legitimate and should complete successfully.
You can use this article to troubleshoot longer-than-expected search response times. If following these recommendation doesn’t improve the Coveo response time, contact Coveo Support.
Search performance or load tests must be planned with and authorized by Coveo.
Assessing search response time
In a Coveo JavaScript Search Framework search page, you can see the total search response time for a query above the corresponding search results.
Response time optimization tips
For Coveo international users
Consider a multi-region deployment
The primary deployment region of all Coveo organizations is either the Eastern United States, Ireland or Australia. This implies that all queries made by end users must travel to that region and back. Thus, end users who aren’t located close to your primary deployment region would experience longer search request delays than end users who are. To improve search request time for end users not located close to your primary deployment region, you will likely want to consider deploying over satellite regions (see Multi-Region Deployments).
For all Coveo users
Shortness
When making natural language queries, keep them short. Long natural language queries could take more time to process, as they may contain frequent terms matching many irrelevant items. Moreover, since a blank space is considered as an AND
Boolean operator by default, a query with many keywords could lead to a long response time or expected results not returned.
Boolean operators
If possible, when building queries with Boolean operators, use as few OR
as possible. A query with an OR
operator may return a very large number of results. Since the result ranking process duration is proportional to the number of results to rank, this operator may impact search response time negatively.
Wildcards
Use the wildcard character (*
) only when necessary, and only in keywords queries with at least two characters before the wildcard character (see Wildcard Operators and Wildcard Constraints). Since the wildcard character represents one or more characters, finding all possible variations in the index takes time. The more precise the context around the wildcard character, the less items match the query, and the less time it takes to return these items.
For Coveo administrators
Precision
-
Make your queries as precise as possible, with as few common or general terms as possible. The less precise the query, the more time it takes to get significant results back.
-
Exact match operators help narrowing your search, as they filter out all items that don’t contain the queried expression. However, exact match expressions are more complex to evaluate than regular keywords, since the keyword positions must be loaded to determine whether the keywords are located next to each other.
Simplicity
Simplify your queries as much as possible.
The following expression creates a very complex syntax tree, which leads to many individual node (for example, @filter=value
) evaluations.
@filter = A OR @filter = B OR @filter = C OR @filter = D OR @filter = E OR @filter = F OR @filter = G OR @filter = H OR @filter = I OR @filter = J OR @filter = K OR @filter = L OR @filter = M OR @filter = N OR @filter = O OR @filter = P OR @filter = Q OR @filter = R
The following construction is more efficient:
@filter = (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R)
Comparison operators
-
When searching for the value of a facet field, use the Is Exactly operator (
==
) (see Add or edit a field). When searching for the value of a field that isn’t used to build a facet, use the Contains operator (=
), unless you must match the exact field value.You have a Web source named
MyCompany
for your company’s external website. If you want to filter documents of that source, you can use one of the following filters:-
@source == "mycompany"
-
@source = "mycompany"
If you choose the first option, only results whose
source
field value is exactlymycompany
, that is, only results from yourMyCompany
source, are displayed. If you choose the second option, all results whosesource
field value containsmycompany
are displayed, such as content from your sources namedMy Company Employee Portal
orMyCompany Customer Database
. Content from yourMyCompany
source is displayed as well.You might expect the search with the Is Exactly operator to be slower since it’s more restrictive and must make sure that there are no other characters before or after the queried value. When used with a facet field, it’s actually faster than a Contains operator search, because only one facet value is loaded in the search results.
If the field isn’t used to build a facet, using the Is Exactly operator when not necessary indeed makes the search process slower.
-
-
Conversely, the Excludes operator (
<>
), which requires results to have a field value different from that queried, doesn’t leverage the facet structure to speed up the query process. Response time is therefore negatively impacted. Use the NOT operator to optimize your search (see Boolean Operators).@author NOT @author == "John Smith"
returns results faster than@author <> "John Smith"
.
For more information, see Comparison Operators.
Field options
-
Enable the Facet, Multi-value facet, Sortable, and Free text search options only for fields that require such options, since they can impact index performance (see About Fields).
-
Enable the Displayable in results option only for fields whose value you want to return along with the search results. Applying this option to certain fields only minimizes the data to be returned by the server, but the impact on response time is minor.
-
When sorting results on a custom field, enable the Use cache for sort option. Keeping the field in memory improves response time.
-
A field is referred to as a computed field when facet code is edited to implement a calculation using this field. When using computed fields, enable the Use cache for computed fields option. Keeping the field in memory improves response time.
-
Cardinality is the number of different values a field has. Cardinality has a great impact on nested query performance, especially with string fields, as many values must be processed (see Field Types). When using high-cardinality facets (especially string fields), enable the Use cache for nested queries option.
-
When sorting your search results in a custom way, that is, by field instead of by relevance or date, the response time may not be optimal if the fields aren’t loaded in cache. Therefore, in the field options, enable both Sortable and Use cache for sort options.
For more information, see Field Types.
Facets
-
The injection depth value is the number of search results that are scanned to find possible facet values. The default value (1,000) may be too low if every item has many values for a single facet field. You can edit the injection depth yourself, but you can also contact Coveo Support to ensure it’s adequate, as the larger the injection depth value, the slower the string-field facet (see Editing Components).
-
Some string facet sorting options require more computation than others, which may lead to a longer response time (see Editing Components).
The Occurrences, AlphaAscending, and AlphaDescending options are the fastest algorithms, while ChiSquare takes longer.
-
Avoid creating string facets displaying many values, as this increases facet loading time (see Editing Components). Default number is 5.
-
If most of the indexed items have a different value for a certain string field, avoid making this field a facet field. Loading many values is resource-demanding, and therefore increases response time. However, if you must have this facet in your search interface, enable the Use cache for nested queries option (see Add or edit a field).
-
When configuring range facets, enable cache usage.
For more information, see Using Facets and JavaScript Search Interface Editor.
Advanced field queries
-
Although very powerful, advanced field query operators such as
*=
are more resource-consuming than free-text and comparison operator queries (see Query syntax). Use advanced queries when necessary, and faster operators for better performances. The Use cache for nested queries option can be enabled to cache in memory all the values that occur a single time in the index, which are typically not cached. Even if the setting is named after the nested query feature, the side effect is very beneficial to advanced field operators. -
Similarly, use wildcards judiciously when making advanced queries. Queries that contain wildcards, when applied to the entire index content, are demanding and might lower performances.
For more information, see Advanced Field Queries.
Search results
-
Exclude irrelevant fields from your search results to improve loading time (see Displayable in search results).
-
The number of requested results has a direct impact on query performance, as loading more items from the index takes more time. Keep the number of returned results as low as possible (see Editing Components). Default number is 10. The higher the number, the larger the quantity of items to return, and the slower the operation. Also, result folding and duplicate filtering will impact performance as well. Therefore, for folding, you should limit the number of folded results to 5 inside each top result. By default, only the first two most relevant children are folded (see Folding results).
Result folding and duplicate filtering are mutually exclusive.
-
Ensure that you don’t load a large number of search results per page (see Editing Components). The response time increases with the number of results to load on a page. The default number is typically 10.
Query pipelines rules
-
Keep query pipelines as simple as possible. The more rules you configure in the query pipeline, the more time it takes to process.
-
Use as few synonyms as possible in your thesaurus entries (see Thesaurus leading practices). Synonyms of each queried term are included in the expanded query, so they can add up to make a much longer query, and therefore increase response time.
-
Use query ranking expressions (QREs) wisely (see Manage ranking expression rules). QREs require a significant amount of processing power, so using many QREs can slow down search performance considerably, especially when many results must be returned. Combined use of Coveo Machine Learning (Coveo ML) Automatic Relevance Tuning (ART) models can slow down the search even more, since ART models are trend-based whereas QREs are based on regular ranking values. ART models and QREs are two resource-demanding features, and leveraging them simultaneously would result in an increased search response time.
-
Use a ranking function rather than many QREs with expressions that only differ by their field value (see Ranking Function).
-
Add stop words to your query pipeline to increase the speed at which natural language queries are processed (see Manage stop word rules). These stop words should be extremely common words that appear in all or most indexed items.
a
,are
,be
,for
,in
,is
,of
,the
,to
,you
For more information, see Manage query pipelines.
Nested queries
-
Enable the Use cache for nested queries option for fields you use in nested queries (see Add or edit a field). This improves response time since a smaller number of values must transit between queries during evaluation.
String fields are supported, but nested queries using them have a longer response time than nested queries leveraging numeric field types.
-
If you have a very high cardinality string field (1 million different values or more) on which you perform nested queries, try adding as many constraints as possible in the nested query filter (see Add or edit a field). This minimizes the number of values to be transferred from the inner query to the outer query, therefore improving response time.
-
Although nested queries support a very high number of nested levels, make nested queries with two levels or less whenever possible. Complex nested queries take more time to execute, therefore impacting performance.
Body mapping
If you want to see many or all available metadata in one field, don’t configure a free-text searchable computed index field with all the values of all the item fields, as this could reduce performances. Use the Coveo indexed document body feature instead (see Add or edit a body mapping). It’s a property on an indexed document rather than a field, it’s free-text searchable, and it’s also used to create the document Quick view and provide a search result excerpt.
For developers
constantExpression
queries
constantExpression
queries are conditions narrowing search results automatically on top of all user queries.
-
Put the parts of query expressions that seldom change in
constantExpression
because it’s cached. -
Avoid using date/time operators (now, today, yesterday) in constant expressions, since the date or time they represent change regularly and they can’t be cached. A
constantExpression
containing such an operator would require to be re-evaluated with every query.
If you have already created constant expressions, you may need to optimize them:
-
Enable the Facet option for the involved fields (see Add or edit a field and Field Uses)
-
Ensure that you use the Is Exactly operator instead of the Contains operator (see Comparison Operators)
-
Ensure that your query syntax is as simple as possible (see Simplicity)
-
When a
constantExpression
contains a numeric field with a constant field value, enable the Use cache for numeric queries option.-
@date > 2017/01/01
-
@size > 1000
ConstantExpression
queries that contain temporal references or other dynamic content can’t be cached, as their values must be regularly recomputed.For example,
@eventdate > now - 30d
. -
Query expression filters
Optimize your query expression filters for performance.
NOT @type=="Bridges Customer Individual" NOT @type=="Bridges Customer Organization"
In this example, the filter will be optimal only if the type
field is a facet field. Otherwise, phrase execution will severely impact performance.
$some
query extension
Use the $some
query extension to optimize your natural language queries. This expression lets the index choose the best terms (that is, least common in the index) before executing the query, and requires that items to return only match a fraction of these best terms.
This query extension is especially useful to isolate relevant words in a long string. By filtering irrelevant terms and querying only the most precise terms of a natural language query, you increase your search performance.
-
The
best
and thematch
parameters values can be either absolute or percentage values. -
Items containing more than the number of keywords required by the
match
parameter are ranked higher than items containing the exact specified number.
In a customer support context, one could use the $some
query extension to find similar support cases without having to read the case description and manually select the words to query. Pasting the entire case description in the $some
extension may therefore be more efficient or return better results than a composing regular natural language query.
$some(keywords: this is a simple test to show how to use the extension, best:4, match:50%)
The best
parameter dictates that four terms need to be kept among the rarest ones. Then, items to return should match at least 50% of these four terms, meaning that two terms are required. So best
could choose to keep simple
, test
, demonstrate
and extension
, and items need to match two out of these four terms. Of course, items matching all four terms score higher, as per regular ranking rules.
$valueOfField
string
Use the $valueOfField
string judiciously. Using this string (often in Salesforce Insight Boxes) executes just as many queries when changing contexts (for example, switching between cases) because all $valueOfField
strings reload at the same time, therefore increasing the response time.
Duplicate filtering
This feature filters out duplicates of items that are at least 85% similar to the original.
Duplicate filtering and result folding are mutually exclusive.
The duplicate filtering feature increases response time, especially when applied to many search results. When using this feature, keep the number of returned results as low as possible.
Result folding (or custom filtering)
Result folding groups results based on the value of a field.
Result folding and duplicate filtering are mutually exclusive.
-
The result folding feature increases response time, especially when applied to many search results. When using this feature, keep the number of returned results as low as possible.
-
Also keep the number of child items load per parent item (
range
option) to a minimum, since the parent and child results add up quickly, therefore leading to a increased response time.Your search result page loads 10 parent results per page, and you set the
range
option to 20 child item. Your search result page could therefore load up to 210 results per page, that is, 10 parent results plus up to 20 child results underneath each parent. -
For an optimal response time, the field based on which results are grouped must contain single word values. If not, the filter is much longer to execute, as phrases must be evaluated.
Queries per user
Avoid building a search interface that issues more than one search query per actual user search. One user query should execute only one search call to the index, as additional queries would be more demanding and increase response time.
What’s next
If your response time issues seem to persist, contact Coveo Support for help and further investigation.