Best practices
Client application developers must communicate with the OpenTV Platform in the most effective way possible. Each unnecessary query or piece of data retrieved slows down the performance of the application and puts unnecessary additional load on the platform, reducing performance or increasing cost. Processing cycles used up by the application when it processes data can have a negative impact on perceived performance if the user is trying to navigate around the application at the same time.
This page provides a number of optimisation techniques when developing a client application that uses the OpenTV platform.
Metadata retrieval
Paging
Several APIs support paging data. Use this functionality to only retrieve the number of items you can display on the screen at once. You can fetch additional items if the user requests them or use pre-fetching to dynamically retrieve additional items as the user navigates so that they do not perceive any data gaps. Do not retrieve everything at once just because it is easier or because it may make future navigation more performant. Each item retrieved takes up server processing time, bandwidth, client processing time and memory to store.
Data fields
Several APIs allow you to specify the fields you want returned. Use this functionality to only return the data you need in the application, either to display or help execute some function. A field does not have to be returned even if it is involved in the query. For example, to get the first five root catalogue nodes, but only the "id" and "Title" fields.
http://server:port/metadata/delivery/vod/nodes?filter={"locale":"en_GB","isRoot":"true"}&limit=5&fields=["id","Title"]&sort=[["cmsOrder",1]]&version=20130603134426
Mandatory fields
Some fields, such as "version" and "total_records", will always be returned irrespective of what fields are requested.
Limit date range queries when using multiple values
Specifically when doing a date range query for events, its seems obvious to simply specify a start date < Y, end date > X, where X is the start point of your viewing window, and Y is the end. The service will apply these filters in order, so when filtering for events with a start date < Y, it can still leave a large amount of events to then filter on again using end date > X. To improve this, also specify start date > Y - n, where n is a reasonably large value that you can guarantee an event will not start before, for example 12 or 24 hours. This means that the end date filter is applied to a much small number of events.
The diagram below shows how a 'start < Y' query with no lower bound will require MDS to consider a large subset of the index for the 'end > X' part of the query.
The part of the index considered for the second part of the query that does not actually satisfy it, is large (and as such has a performance impact). If the following restriction on start is applied instead, for example 'Y-n < start < Y', the subset of the index considered is much smaller.
Sorts must be backed by an index and apply a restrictive filter to sorted queries
Sort the data returned only when it is required by the UI. Using a sort function (without any index) means that the service must first load all relevant data after a filter into memory in order to sort it. To prevent MDS loading a great deal of data into memory, and causing performance issues on the platform, it is critical that queries (as mentioned below) are communicated with the system operator so that they can index the sorting functions. Also, to restrict the amount of sorting that must be done, apply the strictest filter you can to minimize the sort size.
Use caching and versions / if modified since
Several APIs support versions in the requests and responses. A version represents the state of the data, and will change as the data changes. The MDS supports two different methods of interaction with versions of the metadata catalogue: If Modified Since and Versions.
If Modified Since
Metadata server natively supports If-Modified-Since semantics, which is ideal for clients / caching proxies to re-validate their caches of metadata.
MDS is able to check whether data has changed without hitting its database, so a 304 response is a very quick operation.
The diagram below shows the general use of the If-Modified-Since flow:
Although the majority of MDS APIs support this workflow, some APIs are dynamically changed at times other than ingest. The /vod/editorials APIs do not currently respond with 304 at any time.
Versions
An alternative to If-Modified-Since is the built-in version number. Each response from the appropriate MDS APIs include the version number which can be used by client applications to detect changes in data that they should act on or to safely cache data. For example, as a client application downloads parts of a VOD catalogue tree, it could cache the tree in memory. Without versioning, it would either have to not cache, or periodically update the tree to ensure it had the latest version. With versioning, the app knows when something has changed, and therefore can persist the same tree until then, without making expensive calls to get the tree again. For example, to retrieve the version number for the VOD catalogue in MDS.
http: //server:port/metadata/delivery/vod/version
{ "version" : "20130603134426" }
Any responses will also contain the version number with the response JSON.
http: //server:port/metadata/delivery/vod/nodes?limit=1&pretty=true
{
"nodes" : [
{
"BarkerChannelRef" : "TEST" ,
...
"title" : "Destacados" ,
}
],
"total_records" : 136 ,
"version" : "20130603134426"
}
It also important to use versioning for server-side caching to work properly. Without a version number specified in a request, a server-side cache might not update the response to the query for some time after the data has changed. If a version number is supplied, a data change will result in a cache miss that will force the server-side cache to update its data. For example, to query the above nodes API again with a version number:
http: //server:port/metadata/delivery/vod/nodes?limit=1&pretty=true&version=20130603134426
If the data had not changed, the same response (presumably returned by the cache) would be seen; if it had changed, the following would be returned:
{
"latest": "20130603135154",
"msg": "Invalid version of data requested, please use latest",
"requested": "20130603134426"
}
Optimize queries for cache-hits
Each query to the service platform should be optimized to maximize cache hits. This means avoiding sending filter values that frequently change between clients.
Time-based queries
Time values are usually specified by UNIX epoch time, or timestamps. Using time-based on a specific second can cause queries to vary greatly between clients as they each generate the time based on the current moment. Instead, round the time up or down to the coarsest value that makes sense for the use case. For example, if querying for events to populate an EPG guide, and start and end times for the window need to be provided, round the times to the closest fifteen-minute interval. This will mean that each client will send the same query for an interval of time, thereby maximizing the server-side cache-hit.
Structured pre-fetch
When pre-fetching data, try to keep the pattern of fetching additional data the same across devices. For example, if the user enters the EPG grid at the same position each time, and the navigation is via paging rather than scrolling, events can be fetched for that channel group, which should be the same for each channel. If the user is able to scroll down one channel at a time however, events should be fetched on a per channel basis to ensure that only the needed data is returned, and that each query can be effectively cached by the server
Discuss queries with the system operator
The services that implement the APIs can often be tuned for specific use cases. A good example are database indexes where adding one for a key field in a query can dramatically improve the search time for specific records. Client application developers should provide the operator responsible for the platform that they use with a list of the APIs their application uses including all of the filters, fields, sorts, limit and so on so that system can be tuned as much as possible on the server side. This list should be actively maintained as the application remains in progress.
Use gzip to reduce response size
By default, MDS does not compress its responses. You can significantly reduce the size of the response payloads by enabling gzip compression.
To do this, set the Accept-Encoding
header as follows:
Accept-Encoding: gzip