# How-to guide for using the ElasticSearch VOD endpoints

The IOIO VOD/Broker service allows for searching through the VOD's using ElasticSearch queries. To achieve greater granularity using various search criteria there is a search endpoint which is exposed in the broker API.

Prerequisites:

  • Broker Swagger
  • API Key or JWT Token for editing VOD's

To access the elastic API you'd need to have access to the Broker Swagger. This should have been sent to you via email or any other form of communication. Once the swagger is opened, there is a section in it named Elastic:

Elastic_VOD

As we can see there are three endpoints in it. With the first two having differences in the path. That is due to the different authentication methods that these endpoints are using. When there is /private/ in the path it means that this endpoint uses an API key for authentication.

These two endpoints are used for forced syncing of the index which stores data related to the VOD's. Full sync is required only when the complete ElasticSearch index has been deleted and all of the data needs to be created again in the ElasticSearch service.

The endpoint that is used for searching through the VOD's is the third one: Elastic_VOD_Search

What the endpoint does is it allows us to run an ElasticSearch query via the API. Also we can search in two resources:

  • source
  • caption
  1. Source is what the VOD's are called, they represent the videos in the IOIO VOD system. Using the ElasticSearch we can search through the various fields of a source VOD.
  2. Caption is the closed captions/subtitles which are attached to each source VOD. All of the captions for a VOD are listed in the ElasticSearch service so we can search via a phrase in the captions and find exactly where in the VOD is that phrase being said.

# Example queries

Note that due to the many fields which a VOD contains there is only one result listed in the examples below

  1. Simple query searching in the title of a VOD:
{
  "from": 0,
  "size": 10,
  "query": {
	"query_string": {
	  "query": "Sonic",
          "fields":["meta.title"]
	}
  }
}

Using the query above we set our limit to 10 results, the keyword we are using is "Sonic" and we are searching in the title which is located in the meta structure. What we receive with this query is the following result:

{
  "status": true,
  "data": {
    "took": 21,
    "timed_out": false,
    "_shards": {
      "total": 5,
      "successful": 5,
      "skipped": 0,
      "failed": 0
    },
    "hits": {
      "total": {
        "value": 5,
        "relation": "eq"
      },
      "max_score": 6.446238,
      "hits": [
        {
          "_index": "a272539d-dae4-4141-a34f-1a0f508d8f03-source",
          "_type": "_doc",
          "_id": "e9af7794-b64c-42f6-95d4-65db14753ba4",
          "_score": 6.446238,
          "_source": {
            "guid": "e9af7794-b64c-42f6-95d4-65db14753ba4",
            "mediaType": "source",
            "meta": {
              "originalFileName": "sonic_the_eggdog_10_hours.mp4",
              "imageUrl": "https://qa2.stg.ioio.tv/sources/e9af7794-b64c-42f6-95d4-65db14753ba4/thumbnails/2712cbfc-fd7b-484e-9d83-065f918d9011_abr_tumb.0000634.jpg",
              "title": "Sonic the EggDogg 4 Hours",
              "type": "source"
            },
            "srcDuration": 14400042,
            "frameCapture": true,
            "srcVideo": "2712cbfc-fd7b-484e-9d83-065f918d9011.mp4",
            "status": "complete",
            "frameWidth": 640,
            "frameHeight": 360,
            "createdAt": 1629896402000,
            "encodedAt": 1629897969000,
            "hlsUrl": "https://qa2.stg.ioio.tv/broker/vod/hls/e9af7794-b64c-42f6-95d4-65db14753ba4.m3u8",
            "mp4Outputs": [
              "https://qa2.stg.ioio.tv/sources/e9af7794-b64c-42f6-95d4-65db14753ba4/mp4/2712cbfc-fd7b-484e-9d83-065f918d9011_360p.mp4"
            ],
            "parentGuid": "5dba4ea4-75d0-440f-99db-56013cdcd0fa",
            "clipperGuid": "300838fb-5e86-40ad-8845-6ebcd69ba301",
            "sourceProxy": {
              "guid": "e9af7794-b64c-42f6-95d4-65db14753ba4",
              "mediaType": "source-proxy",
              "status": "complete",
              "createdAt": 1629896407000,
              "encodedAt": 1629897603000,
              "proxyUrl": "https://qa2.stg.ioio.tv/sources/e9af7794-b64c-42f6-95d4-65db14753ba4/proxy/2712cbfc-fd7b-484e-9d83-065f918d9011_proxy.mp4"
            },
            "mediaInfo": {
              "filename": "2712cbfc-fd7b-484e-9d83-065f918d9011.mp4",
              "container": {
                "format": "MPEG-4",
                "fileSize": 2535197366,
                "duration": 14400.043,
                "totalBitrate": 1408439
              },
              "video": [
                {
                  "codec": "AVC",
                  "profile": "High@L4",
                  "bitrate": 1275778,
                  "duration": 14400.042,
                  "frameCount": 345601,
                  "width": 640,
                  "height": 360,
                  "framerate": 24,
                  "scanType": "Progressive",
                  "aspectRatio": "1.778",
                  "bitDepth": 8,
                  "colorSpace": "YUV 4:2:0"
                }
              ],
              "audio": [
                {
                  "codec": "AAC",
                  "bitrate": 128000,
                  "duration": 14400.043,
                  "frameCount": 337501,
                  "bitrateMode": "VBR",
                  "language": "en",
                  "channels": 2,
                  "samplingRate": 48000,
                  "samplePerFrame": 2048
                }
              ]
            },
            "thumbsData": {
              "pattern": "https://qa2.stg.ioio.tv/image-external/3dcfcfcc-a6ca-44a6-bf18-6dee7b2c26d0/sources/{prefix}{imageNumber}{suffix}",
              "firstNumber": 0,
              "lastNumber": 999,
              "prefix": "e9af7794-b64c-42f6-95d4-65db14753ba4/thumbnails/2712cbfc-fd7b-484e-9d83-065f918d9011_abr_tumb.",
              "numberOfZeroes": 7,
              "suffix": ".jpg"
            },
            "resourceType": "source"
          }
        }

Each of the results has a score. The higher the score the closer is the result to the search phrase. Results are arranaged in a descending manner with the highest score being returned first and result with the lowest score is last.

  1. Query searching in the Title and Description of a VOD.
{
  "from": 0,
  "size": 10,
  "query": {
	"query_string": {
	  "query": "test",
          "fields":["meta.title","meta.description"]
	}
  }
}

This query returns the following result:

{
  "status": true,
  "data": {
    "took": 473,
    "timed_out": false,
    "_shards": {
      "total": 5,
      "successful": 5,
      "skipped": 0,
      "failed": 0
    },
    "hits": {
      "total": {
        "value": 237,
        "relation": "eq"
      },
      "max_score": 11.37868,
      "hits": [
        {
          "_index": "a272539d-dae4-4141-a34f-1a0f508d8f03-source",
          "_type": "_doc",
          "_id": "f2abe4f6-1cb1-4550-bf0a-cdfe02ee01e0",
          "_score": 11.37868,
          "_source": {
            "guid": "f2abe4f6-1cb1-4550-bf0a-cdfe02ee01e0",
            "mediaType": "source",
            "meta": {
              "originalFileName": "2021-11-12-11-54-03.ts",
              "imageUrl": "https://qa2.stg.ioio.tv/sources/f2abe4f6-1cb1-4550-bf0a-cdfe02ee01e0/thumbnails/1a31e995-e0cf-453e-aa10-f12bfff10a13_mp4_tumb.0000041.jpg",
              "description": "No other video should have this",
              "type": "source",
              "title": "Clipper"
            },
            "srcDuration": 245033,
            "frameCapture": true,
            "srcVideo": "1a31e995-e0cf-453e-aa10-f12bfff10a13.mp4",
            "status": "complete",
            "frameWidth": 1920,
            "frameHeight": 1080,
            "createdAt": 1637756762000,
            "encodedAt": 1637756885000,
            "hlsUrl": "https://qa2.stg.ioio.tv/broker/vod/hls/f2abe4f6-1cb1-4550-bf0a-cdfe02ee01e0.m3u8",
            "mp4Outputs": [
              "https://qa2.stg.ioio.tv/sources/f2abe4f6-1cb1-4550-bf0a-cdfe02ee01e0/mp4/1a31e995-e0cf-453e-aa10-f12bfff10a13_360p.mp4"
            ],
            "parentGuid": "6b95d772-88cb-4ac9-aca4-3a9090ecbddf",
            "clipperGuid": "fdf32c44-d09c-42db-8ea3-871abfc49196",
            "sourceProxy": {
              "guid": "f2abe4f6-1cb1-4550-bf0a-cdfe02ee01e0",
              "mediaType": "source-proxy",
              "status": "complete",
              "createdAt": 1637756763000,
              "encodedAt": 1637756822000,
              "proxyUrl": "https://qa2.stg.ioio.tv/sources/f2abe4f6-1cb1-4550-bf0a-cdfe02ee01e0/proxy/1a31e995-e0cf-453e-aa10-f12bfff10a13_proxy.mp4"
            },
            "mediaInfo": {
              "filename": "1a31e995-e0cf-453e-aa10-f12bfff10a13.mp4",
              "container": {
                "format": "MPEG-4",
                "fileSize": 10078534,
                "duration": 245.035,
                "totalBitrate": 329048
              },
              "video": [
                {
                  "codec": "AVC",
                  "profile": "High@L4",
                  "bitrate": 194624,
                  "duration": 245.033,
                  "frameCount": 7351,
                  "width": 1920,
                  "height": 1080,
                  "framerate": 30,
                  "scanType": "Progressive",
                  "aspectRatio": "1.778",
                  "bitDepth": 8,
                  "colorSpace": "RGB 4:2:0"
                }
              ],
              "audio": [
                {
                  "codec": "AAC",
                  "bitrate": 128000,
                  "duration": 245.035,
                  "frameCount": 5743,
                  "bitrateMode": "VBR",
                  "channels": 2,
                  "samplingRate": 48000,
                  "samplePerFrame": 2048
                }
              ]
            },
            "thumbsData": {
              "pattern": "https://qa2.stg.ioio.tv/image-external/3dcfcfcc-a6ca-44a6-bf18-6dee7b2c26d0/sources/{prefix}{imageNumber}{suffix}",
              "firstNumber": 0,
              "lastNumber": 49,
              "prefix": "f2abe4f6-1cb1-4550-bf0a-cdfe02ee01e0/thumbnails/1a31e995-e0cf-453e-aa10-f12bfff10a13_abr_tumb.",
              "numberOfZeroes": 7,
              "suffix": ".jpg"
            },
            "resourceType": "source"
          }
        }

As we can see the entire description is matched and the VOD is returned at first place with the highest score.

Of course we can have the results sorted by a another field, be that a date, duration and so on. So here is an example which uses the "sort" option:

{
  "from": 0,
  "size": 10,
  "query": {
	"query_string": {
	  "query": "Sonic",
          "fields":["meta.title","meta.description"]
	}
  },
  "sort": [
    {
      "createdAt": {
        "order": "desc"
      }
    }
  ]
}

The result from this query is:

{
  "status": true,
  "data": {
    "took": 784,
    "timed_out": false,
    "_shards": {
      "total": 5,
      "successful": 5,
      "skipped": 0,
      "failed": 0
    },
    "hits": {
      "total": {
        "value": 5,
        "relation": "eq"
      },
      "max_score": null,
      "hits": [
        {
          "_index": "a272539d-dae4-4141-a34f-1a0f508d8f03-source",
          "_type": "_doc",
          "_id": "8facf6e9-460e-42f2-9647-ddec0acefb23",
          "_score": null,
          "_source": {
            "guid": "8facf6e9-460e-42f2-9647-ddec0acefb23",
            "mediaType": "source",
            "meta": {
              "originalFileName": "sonic_the_eggdog_10_hours.mp4",
              "encodeLater": "1",
              "title": "Sonic the EggDogg 3:59:59 Hours",
              "type": "source",
              "captionsGuid": "a37d4c66-6b57-45ef-84ca-87abbe3ba2d8"
            },
            "srcDuration": 14399042,
            "frameCapture": true,
            "srcVideo": "de905dc1-fea5-4c53-856a-a6461905a5ca.mp4",
            "status": "encode-later",
            "frameWidth": 640,
            "frameHeight": 360,
            "createdAt": 1629898206000,
            "parentGuid": "c6367001-b892-4730-ab55-77299e29605a",
            "clipperGuid": "84df38ae-5e17-4c9f-bdce-e013e3d6488f",
            "sourceProxy": {
              "guid": "8facf6e9-460e-42f2-9647-ddec0acefb23",
              "mediaType": "source-proxy",
              "status": "complete",
              "createdAt": 1629898209000,
              "encodedAt": 1629899468000,
              "proxyUrl": "https://qa2.stg.ioio.tv/sources/8facf6e9-460e-42f2-9647-ddec0acefb23/proxy/de905dc1-fea5-4c53-856a-a6461905a5ca_proxy.mp4"
            },
            "mediaInfo": {
              "filename": "de905dc1-fea5-4c53-856a-a6461905a5ca.mp4",
              "container": {
                "format": "MPEG-4",
                "fileSize": 2433780310,
                "duration": 14399.042,
                "totalBitrate": 1352190
              },
              "video": [
                {
                  "codec": "AVC",
                  "profile": "High@L4",
                  "bitrate": 1219530,
                  "duration": 14399.042,
                  "frameCount": 345577,
                  "width": 640,
                  "height": 360,
                  "framerate": 24,
                  "scanType": "Progressive",
                  "aspectRatio": "1.778",
                  "bitDepth": 8,
                  "colorSpace": "YUV 4:2:0"
                }
              ],
              "audio": [
                {
                  "codec": "AAC",
                  "bitrate": 128000,
                  "duration": 14399.019,
                  "frameCount": 337477,
                  "bitrateMode": "VBR",
                  "language": "en",
                  "channels": 2,
                  "samplingRate": 48000,
                  "samplePerFrame": 2048
                }
              ]
            },
            "resourceType": "source"
          },
          "sort": [
            1629898206000
          ]
        }

One thing to note when using the sort option is that score no longer has any value, it is instead null since it is no longer relevant to our search query.

  1. Searching in the captions of a VOD

To search in the captions of a VOD we need to change the resource type to caption: Elastic_VOD_Search

Also here's a CURL for the same request:

curl -X POST "https://rsghrbyn64.execute-api.eu-west-1.amazonaws.com/dev/broker/search?resource=caption" -H  "accept: application/json" -H  "Content-Type: application/json" -d "{  \"from\": 0,  \"size\": 10,  \"query\": {\t\"query_string\": {\t  \"query\": \"We're in Brownsville now.\"\t}  }}"

Response from the query above is:

{
  "status": true,
  "data": {
    "took": 101,
    "timed_out": false,
    "_shards": {
      "total": 5,
      "successful": 5,
      "skipped": 0,
      "failed": 0
    },
    "hits": {
      "total": {
        "value": 371,
        "relation": "eq"
      },
      "max_score": 7.729467,
      "hits": [
        {
          "_index": "a272539d-dae4-4141-a34f-1a0f508d8f03-caption",
          "_type": "_doc",
          "_id": "2b603a3f-4214-4c2c-84b1-76ca78bc938a",
          "_score": 7.729467,
          "_source": {
            "sourceGuid": "e7269b97-457b-4cfb-810c-515b4a8b822f",
            "meta": {
              "description": "ENG Subs",
              "lang": "ENG"
            },
            "content": {
              "valid": true,
              "strict": true,
              "cues": [
                {
                  "identifier": "",
                  "start": 0.255,
                  "end": 2.016,
                  "text": "Everyone please stay close.",
                  "styles": ""
                },
                {
                  "identifier": "",
                  "start": 2.018,
                  "end": 4.979,
                  "text": "Keep your pocketbooks tight\nand your heads on a swivel.",
                  "styles": ""
                },
                {
                  "identifier": "",
                  "start": 4.981,
                  "end": 6.425,
                  "text": "We're in Brownsville now.",
                  "styles": ""
                }

As we can see the top result is again based on score. One thing to note is that no metadata for the video to which the captions blong is presented. To identify the VOD we have the sourceGuid through which we can get the details for the VOD.