openapi: 3.1.1

info:
  title: NGRAMS
  description: A search engine for the Google Books Ngram Dataset (version 3).
  contact:
    name: Martin Trenkmann
    email: contact@ngrams.dev
  license:
    name: Creative Commons Attribution 4.0 International
    identifier: CC-BY-4.0
  version: 1.1.0

servers:
  - url: https://api.ngrams.dev
    description: Production server

paths:
  /{corpus}/info:
    get:
      description: Get static information about a corpus.
      responses:
        200:
          description: The request was successful.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CorpusInfo'
    parameters:
      - $ref: '#/components/parameters/corpus'

  /{corpus}/search:
    get:
      description: Search a corpus by wildcard query.
      responses:
        200:
          description: The request was successful.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchResult'
        400:
          description: The request failed due to client error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResult'
      parameters:
        - $ref: '#/components/parameters/corpus'
        - name: query
          in: query
          description: Query string
          required: true
          schema:
            type: string
        - name: flags
          in: query
          description: |
            Concatenated string of search flags.
            - `cs` — Search is case-sensitive.
            - `cr` — Collapse the result set by case-folding and then merging equal ngrams.
            - `ep` — Exclude ngrams from the result set where wildcards matched punctuation marks as of [Unicode category P](https://www.unicode.org/reports/tr44/#General_Category_Values).
            - `es` — Exclude ngrams from the result set where wildcards matched sentence boundary tags, namely `_START_` and `_END_`.
            - `rq` — Raw query: Do not interpret query operators. No need for escape sequences.
          schema:
            type: string
        - name: limit
          in: query
          description: |
            Maximum number of ngrams to return.
            The limit is applied before ngram filtering or collapsing is performed.
            This means that the actual number of ngrams may be smaller if any of the flags
            `cs`, `cr`, `ep`, or `es` are set.
          schema:
            type: integer
            format: int32
            minimum: 0
            maximum: 100
            default: 100
        - name: start
          in: query
          description: |
            Opaque token to fetch the next page of the result set.
            A start token is included in a successful search result if there are possibly more
            matching ngrams.
          schema:
            type: string

  /{corpus}/batch:
    post:
      description: |
        Send up to 100 non-wildcard queries.
        This type of request is to obtain the frequency of multiple ngrams quickly.
        All queries in the batch have the `rq` flag implicitly set.
      requestBody:
        description: A list of non-wildcard queries and search flags.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Batch'
      responses:
        200:
          description: The request was successful.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BatchResult'
        400:
          description: The request failed due to client error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResult'
      parameters:
        - $ref: '#/components/parameters/corpus'

  /{corpus}/{ngramId}:
    get:
      description: Get an ngram object with complete year-based match count information.
      responses:
        200:
          description: The request was successful.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Ngram'
        404:
          description: |
            No ngram found for given ID.
            Note that an abstract ngram has no year-based match count information.
      parameters:
        - $ref: '#/components/parameters/corpus'
        - name: ngramId
          in: path
          required: true
          schema:
            type: string

  /{corpus}/total_counts:
    get:
      description: |
        Get the sum of ngram occurrences by ngram length and year.
        This data is useful for computing the relative frequencies of ngrams.
      responses:
        200:
          description: The request was successful.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TotalCounts'
    parameters:
      - $ref: '#/components/parameters/corpus'

components:
  parameters:
    corpus:
      description: A label denoting a corpus.
      name: corpus
      in: path
      required: true
      schema:
        type: string
        enum:
          - eng
          - ger
          - rus

  schemas:
    Batch:
      description: The body of a batch request.
      type: object
      required:
        - queries
      properties:
        queries:
          description: |
            A list of non-wildcard queries.
            All queries have the `rq` flag implicitly set, i.e. wildcards are not interpreted.
          type: array
          items:
            type: string
          minItems: 1
          maxItems: 100
        flags:
          description: |
            A concatenated string of search flags that will be active for all queries.
            - `cs` — Search is case-sensitive.
            - `cr` — Collapse the result set by case-folding and then merging equal ngrams.
          type: string
        limit:
          description: |
            Maximum number of ngrams to return per query.
            The limit is applied before ngram filtering or collapsing is performed.
            This means that the actual number of ngrams may be smaller if the `cs` or `cr` flag is set.
            A limit of `0` is mapped to the default value.
          type: integer
          minimum: 0
          maximum: 20
          default: 20
      example:
        queries:
          - hello world
          - Hello World
          - HELLO WORLD
        flags: cs

    BatchResult:
      description: The result of a successful batch request.
      type: object
      required:
        - results
      properties:
        results:
          description: |
            A list of results, one for each query.
            
            `results[i]` is the outcome of `queries[i]` in the batch object.
            
            Use the `error` property to discriminate the item type.
          type: array
          items:
            oneOf:
              - $ref: '#/components/schemas/SearchResult'
              - $ref: '#/components/schemas/ErrorResult'
          minItems: 0
          maxItems: 100
      example:
        - queryTokens:
            - text: hello
              kind: TERM
            - text: world
              kind: TERM
          ngrams:
            - id: 92c668bc012dc3e387ff0c7e791528db
              absTotalMatchCount: 118987
              relTotalMatchCount: 5.6675204699428898e-8
              tokens:
                - text: Hello
                  kind: TERM
                - text: World
                  kind: TERM
            - id: 661befe7c71b0ac1aa8d9574a01f6cd8
              absTotalMatchCount: 19795
              relTotalMatchCount: 9.428640750881988e-9
              tokens:
                - text: Hello
                  kind: TERM
                - text: world
                  kind: TERM
            - id: f2036997e2ba2ab5ba39ecc6c8d5a19f
              absTotalMatchCount: 15751
              relTotalMatchCount: 7.502425888716453e-9
              tokens:
                - text: hello
                  kind: TERM
                - text: world
                  kind: TERM
        - error:
            code: INVALID_QUERY.TOO_MANY_TOKENS
          queryTokens:
            - text: one
              kind: TERM
            - text: two
              kind: TERM
            - text: three
              kind: TERM
            - text: four
              kind: TERM
            - text: five
              kind: TERM
            - text: six
              kind: TERM

    CorpusInfo:
      description: Represents static information about a corpus.
      type: object
      discriminator:
        propertyName: label
      required:
        - name
        - label
        - stats
      properties:
        name:
          description: The full name of the corpus.
          type: string
        label:
          description: The short name of the corpus.
          type: string
        stats:
          description: |
            An array containing statistical information about the corpus.
            Index 0 refers to 1-gram stats, index 1 refers to 2-gram stats, and so on.
          type: array
          minItems: 5
          maxItems: 5
          items:
            $ref: '#/components/schemas/CorpusStat'
      example:
        name: English
        label: eng
        stats:
          - numNgrams: 76862879
            minYear: 1470
            maxYear: 2019
            minMatchCount: 1
            maxMatchCount: 1922716631
            minTotalMatchCount: 40
            maxTotalMatchCount: 115513165249
          - numNgrams: 1604084580
            minYear: 1470
            maxYear: 2019
            minMatchCount: 1
            maxMatchCount: 1446928350
            minTotalMatchCount: 40
            maxTotalMatchCount: 82544506739
          - numNgrams: 11777289629
            minYear: 1470
            maxYear: 2019
            minMatchCount: 1
            maxMatchCount: 84854130
            minTotalMatchCount: 40
            maxTotalMatchCount: 2907518961
          - numNgrams: 5089891990
            minYear: 1470
            maxYear: 2019
            minMatchCount: 1
            maxMatchCount: 14391742
            minTotalMatchCount: 40
            maxTotalMatchCount: 384260789
          - numNgrams: 5020506742
            minYear: 1470
            maxYear: 2019
            minMatchCount: 1
            maxMatchCount: 7167265
            minTotalMatchCount: 40
            maxTotalMatchCount: 226361873

    CorpusStat:
      description: |
        Describes statistical information about a corpus.
        All numbers refer to the subset of **indexed** ngrams after filtering.
      type: object
      required:
        - numNgrams
        - minYear
        - maxYear
        - minMatchCount
        - maxMatchCount
        - minTotalMatchCount
        - maxTotalMatchCount
      properties:
        numNgrams:
          description: The number of ngrams in the corpus.
          type: integer
          format: int64
        minYear:
          description: The minimum year value of all ngrams in the corpus.
          type: integer
          format: int32
        maxYear:
          description: The maximum year value of all ngrams in the corpus.
          type: integer
          format: int32
        minMatchCount:
          description: The minimum year-based match count value of all ngrams in the corpus.
          type: integer
          format: int32
        maxMatchCount:
          description: The maximum year-based match count value of all ngrams in the corpus.
          type: integer
          format: int32
        minTotalMatchCount:
          description: The minimum total match count value of all ngrams in the corpus.
          type: integer
          format: int64
        maxTotalMatchCount:
          description: The maximum total match count value of all ngrams in the corpus.
          type: integer
          format: int64
      example:
        numNgrams: 76862879
        minYear: 1470
        maxYear: 2019
        minMatchCount: 1
        maxMatchCount: 1922716631
        minTotalMatchCount: 40
        maxTotalMatchCount: 115513165249

    Error:
      type: object
      required:
        - code
      properties:
        code:
          description: |
            | Value                           | Description                                               |
            |---------------------------------|-----------------------------------------------------------|
            | `INVALID_BATCH_SIZE`            | Number of queries in a batch request was out-of-range     |
            | `INVALID_PARAMETER.LIMIT`       | `limit` parameter not parsable or out-of-range            |
            | `INVALID_PARAMETER.START`       | `start` parameter is invalid                              |
            | `INVALID_QUERY.BAD_ALTERNATION` | Token to the left or right of the `/` operator is invalid |
            | `INVALID_QUERY.BAD_COMPLETION`  | The `~` operator has no prefix in front of it             |
            | `INVALID_QUERY.BAD_TERM_GROUP`  | Opening quotation mark without closing quotation mark     |
            | `INVALID_QUERY.NO_TERM`         | Query has no search term                                  |
            | `INVALID_QUERY.TOO_EXPENSIVE`   | Query is too expensive to process and was rejected        |
            | `INVALID_QUERY.TOO_MANY_TOKENS` | Query has more than 5 tokens after tokenization           |
            | `INVALID_REQUEST_BODY`          | Body of batch request not parsable or has wrong schema    |
            | `INVALID_UTF8_ENCODING`         | Query string is not in UTF-8 format                       |
            | `MISSING_PARAMETER.QUERY`       | `query` parameter is missing                              |
          type: string
          enum:
            - INVALID_BATCH_SIZE
            - INVALID_PARAMETER.LIMIT
            - INVALID_PARAMETER.START
            - INVALID_QUERY.BAD_ALTERNATION
            - INVALID_QUERY.BAD_COMPLETION
            - INVALID_QUERY.BAD_TERM_GROUP
            - INVALID_QUERY.NO_TERM
            - INVALID_QUERY.TOO_EXPENSIVE
            - INVALID_QUERY.TOO_MANY_TOKENS
            - INVALID_REQUEST_BODY
            - INVALID_UTF8_ENCODING
            - MISSING_PARAMETER.QUERY
        context:
          description: |
            Contains error-specific context information for advanced error handling.
            The exact format is currently work in progress. Do not use.
          type:
            - object
            - string
      example:
        code: INVALID_QUERY.TOO_MANY_TOKENS

    ErrorResult:
      description: Represents the result of a failed search request.
      type: object
      required:
        - error
      properties:
        error:
          $ref: '#/components/schemas/Error'
        query:
          description: The user query.
          type: string
        queryTokens:
          description: |
            The tokenized user query.
            This property is only available if query processing has actually taken place.
            It is not available if a request was rejected at an earlier stage, e.g. due to missing
            required parameters.
          type: array
          items:
            $ref: '#/components/schemas/QueryToken'
      example:
        error:
          code: INVALID_QUERY.TOO_MANY_TOKENS
        query: 'one two three four five *'
        queryTokens:
          - text: one
            kind: TERM
          - text: two
            kind: TERM
          - text: three
            kind: TERM
          - text: four
            kind: TERM
          - text: five
            kind: TERM
          - text: '*'
            kind: STAR

    Ngram:
      description: |
        Represents an ngram with basic metadata and complete year-based match count information.
      allOf:
        - $ref: '#/components/schemas/NgramLite'
        - type: object
          required:
            - stats
          properties:
            stats:
              description: A list of year-based match counts.
              type: array
              items:
                $ref: '#/components/schemas/NgramStat'
      example:
        id: f2036997e2ba2ab5ba39ecc6c8d5a19f
        absTotalMatchCount: 15751
        relTotalMatchCount: 7.502425888716453e-9
        tokens:
          - text: hello
            kind: TERM
          - text: world
            kind: TERM
        stats:
          - year: 1880
            absMatchCount: 21
            relMatchCount: 4.889791590572001e-9
          - year: 1900
            absMatchCount: 17
            relMatchCount: 2.1000682472890535e-9
          - year: 1901
            absMatchCount: 1
            relMatchCount: 1.1991136888826875e-10

    NgramLite:
      description: |
        Represents an ngram with basic metadata but without year-based match count information.
      type: object
      required:
        - id
        - absTotalMatchCount
        - relTotalMatchCount
        - tokens
      properties:
        id:
          description: The ngram ID that identifies the ngram uniquely within a corpus.
          type: string
        absTotalMatchCount:
          description: |
            The ngram's absolute total match count, i.e. the sum of all its year-based match counts.
          type: integer
          format: int64
        relTotalMatchCount:
          description: |
            The ngram's relative total match count, i.e. its absolute total match count divided by
            the absolute total match count of all ngrams in the corpus.
          type: number
          format: double
        abstract:
          description: |
            Indicates whether the ngram is abstract as a result of applying result set collapsing.
            An abstract ngram does not represent an existing ngram from the dataset and hence has
            no associated year-based match count information. Nevertheless, its ID is unique within
            a corpus.
          type: boolean
        tokens:
          description: A list of the ngram's tokens.
          type: array
          items:
            $ref: '#/components/schemas/NgramToken'
          minItems: 1
          maxItems: 5
      example:
        id: f2036997e2ba2ab5ba39ecc6c8d5a19f
        absTotalMatchCount: 15751
        relTotalMatchCount: 7.502425888716453e-9
        tokens:
          - text: hello
            kind: TERM
          - text: world
            kind: TERM

    NgramStat:
      description: |
        Represents an ngram's match count of a specific year.
        This data corresponds to one line of metadata from the original dataset as described
        [here](https://storage.googleapis.com/books/ngrams/books/datasetsv3.html).
        
        - Note that `volume_count` has not been indexed.
        - Note that `relMatchCount` is derived data using total match count information.
      type: object
      required:
        - year
        - absMatchCount
        - relMatchCount
      properties:
        year:
          description: The year of publication.
          type: integer
          format: int32
        absMatchCount:
          description: |
            The ngram's absolute frequency. Corresponds to `match_count` in original dataset.
          type: integer
          format: int64
        relMatchCount:
          description: |
            The ngram's relative frequency derived from `absMatchCount` and `/{corpus}/total_counts`.
          type: number
          format: double
      example:
        year: 2000
        absMatchCount: 51557
        relMatchCount: 0.0000020760804297569299

    NgramToken:
      description: |
        A single token as part of a tokenized ngram. If contained in a search result,
        it also includes metadata to correlate the token with tokens from the respective query,
        i.e. if the token was part of the input, or has been inserted, or has been completed.
      type: object
      required:
        - text
        - kind
      properties:
        text:
          description: |
            The token's text in stripped form.
            For regular terms like `hello` this is `hello`.
            For part-of-speech tagged terms like `word_NOUN` this is just `word`.
            The part-of-speech suffix can be reconstructed from `kind` property.
          type: string
        kind:
          description: |
            | Value            | Description                   |
            |------------------|-------------------------------|
            | `TERM`           | Token is a regular term       |
            | `TAGGED_AS_ADJ`  | Token has a POS tag of `ADJ`  |
            | `TAGGED_AS_ADP`  | Token has a POS tag of `ADP`  |
            | `TAGGED_AS_ADV`  | Token has a POS tag of `ADV`  |
            | `TAGGED_AS_CONJ` | Token has a POS tag of `CONJ` |
            | `TAGGED_AS_DET`  | Token has a POS tag of `DET`  |
            | `TAGGED_AS_NOUN` | Token has a POS tag of `NOUN` |
            | `TAGGED_AS_NUM`  | Token has a POS tag of `NUM`  |
            | `TAGGED_AS_PRON` | Token has a POS tag of `PRON` |
            | `TAGGED_AS_PRT`  | Token has a POS tag of `PRT`  |
            | `TAGGED_AS_VERB` | Token has a POS tag of `VERB` |
            | `SENTENCE_START` | Token is the `_START_` token  |
            | `SENTENCE_END`   | Token is the `_END_` token    |
          type: string
          enum:
            - TERM
            - TAGGED_AS_ADJ
            - TAGGED_AS_ADP
            - TAGGED_AS_ADV
            - TAGGED_AS_CONJ
            - TAGGED_AS_DET
            - TAGGED_AS_NOUN
            - TAGGED_AS_NUM
            - TAGGED_AS_PRON
            - TAGGED_AS_PRT
            - TAGGED_AS_VERB
            - SENTENCE_START
            - SENTENCE_END
        inserted:
          description: |
            Indicates whether the token was inserted from applying the `*`, or `**`, or `*_ADJ`
            (and friends) wildcard.
          type: boolean
        completed:
          description: Indicates whether the token was completed from applying the `~` operator.
          type: boolean
      example:
        text: world
        kind: TERM
        inserted: true

    QueryToken:
      description: Represents a single token as part of a tokenized user query.
      type: object
      required:
        - text
        - kind
      properties:
        text:
          type: string
        kind:
          description: |
            | Value            | Description                    |
            |------------------|--------------------------------|
            | `TERM`           | Token is a regular query term  |
            | `STAR`           | Token is the `*` wildcard      |
            | `STARSTAR`       | Token is the `**` wildcard     |
            | `STAR_ADJ`       | Token is the `*_ADJ` wildcard  |
            | `STAR_ADP`       | Token is the `*_ADP` wildcard  |
            | `STAR_ADV`       | Token is the `*_ADV` wildcard  |
            | `STAR_CONJ`      | Token is the `*_CONJ` wildcard |
            | `STAR_DET`       | Token is the `*_DET` wildcard  |
            | `STAR_NOUN`      | Token is the `*_NOUN` wildcard |
            | `STAR_NUM`       | Token is the `*_NUM` wildcard  |
            | `STAR_PRON`      | Token is the `*_PRON` wildcard |
            | `STAR_PRT`       | Token is the `*_PRT` wildcard  |
            | `STAR_VERB`      | Token is the `*_VERB` wildcard |
            | `SENTENCE_START` | Token is the `_START_` token   |
            | `SENTENCE_END`   | Token is the `_END_` token     |
            | `SLASH`          | Token is the `/` operator      |
            | `PREFIX`         | Token has the `~` operator     |
            | `TERM_GROUP`     | Token is a term group          |
          type: string
          enum:
            - TERM
            - STAR
            - STARSTAR
            - STAR_ADJ
            - STAR_ADP
            - STAR_ADV
            - STAR_CONJ
            - STAR_DET
            - STAR_NOUN
            - STAR_NUM
            - STAR_PRON
            - STAR_PRT
            - STAR_VERB
            - SENTENCE_START
            - SENTENCE_END
            - SLASH
            - PREFIX
            - TERM_GROUP
      example:
        text: hello
        kind: TERM

    SearchResult:
      description: Represents the result of a successful search request.
      type: object
      required:
        - query
        - queryTokens
        - ngrams
      properties:
        query:
          description: The user query.
          type: string
        queryTokens:
          description: The tokenized user query.
          type: array
          items:
            $ref: '#/components/schemas/QueryToken'
        ngrams:
          description: A list of matching ngrams.
          type: array
          items:
            $ref: '#/components/schemas/NgramLite'
          maxItems: 100
        nextPageToken:
          description: An opaque token to use to fetch the next page of the result set.
          type: string
        nextPageLink:
          description: A URL to fetch the next page of the result set.
          type: string
          format: url
      example:
        query: 'hello *'
        queryTokens:
          - text: hello
            kind: TERM
          - text: '*'
            kind: STAR
        ngrams:
          - id: b8c39a9ea59fc987c31c3977e5bc4903
            absTotalMatchCount: 3819827
            relTotalMatchCount: 0.0000018194380658509366
            tokens:
              - text: Hello
                kind: TERM
              - text: ','
                kind: TERM
                inserted: true
          - id: b6bedfb67a66cd8bc756f0bae7401b62
            absTotalMatchCount: 938877
            relTotalMatchCount: 4.4720050226147147e-7
            tokens:
              - text: Hello
                kind: TERM
              - text: '?'
                kind: TERM
                inserted: true
          - id: 8008219f6edd10c83495ad825de723b6
            absTotalMatchCount: 645647
            relTotalMatchCount: 3.075308721841224e-7
            tokens:
              - text: Hello
                kind: TERM
              - text: '.'
                kind: TERM
                inserted: true
        nextPageToken: 76bb10582156abea101f1c82dffa6709c3ab40f2bcc2f447a04f9863c589c53164a2496eaa61c6f8dea57770a6e454d9
        nextPageLink: 'https://cubus.local:8080/eng/search?query=hello+%2A&start=76bb10582156abea101f1c82dffa6709c3ab40f2bcc2f447a04f9863c589c53164a2496eaa61c6f8dea57770a6e454d9'

    TotalCounts:
      description: |
        Represents a lookup table for ngram total match counts by ngram length and year.
        
        The table covers the full range from ngram length 1 to 5 combined with first year to last
        year of ngram occurrence. For combinations where no total match count is available the
        value is zero.
      type: object
      required:
        - minYear
        - maxYear
        - matchCounts
      properties:
        minYear:
          description: The first year of ngram occurrence.
          type: integer
          format: int32
          minimum: 1470
          maximum: 2019
        maxYear:
          description: The last year of ngram occurrence.
          type: integer
          format: int32
          minimum: 1470
          maximum: 2019
        matchCounts:
          description: |
            A matrix of ngram total match counts.
            
            The first subscript in the range `[0, 4]` denotes the ngram length,
            with 1-gram counts at index 0, 2-gram counts at index 1, and so on.
            
            The second subscript in the range `[0, (maxYear - minYear)]` denotes the year,
            with `minYear` at index 0, `minYear + 1` at index 1, and so on.
            
            Example:
            The total match count of 3-grams for the year 2000 in the English corpus is
            `matchCounts[2][530]` because `minYear = 1470` and `2000 - minYear = 530`.
          type: array
          items:
            type: array
            items:
              type: integer
              format: int64
          minItems: 5
          maxItems: 5
      example:
        minYear: 1470
        maxYear: 2019
        matchCounts:
          - [ 984, 0, 117652, '…' ]
          - [ 1019, 0, 122756, '…' ]
          - [ 984, 0, 117652, '…' ]
          - [ 949, 0, 112548, '…' ]
          - [ 914, 0, 107455, '…' ]
