Unsigned long field type

Unsigned long field type

Unsigned long is a numeric field type that represents an unsigned 64-bit integer with a minimum value of 0 and a maximum value of 264-1 (from 0 to 18446744073709551615 inclusive).

  1. resp = client.indices.create(
  2. index="my_index",
  3. mappings={
  4. "properties": {
  5. "my_counter": {
  6. "type": "unsigned_long"
  7. }
  8. }
  9. },
  10. )
  11. print(resp)
  1. response = client.indices.create(
  2. index: 'my_index',
  3. body: {
  4. mappings: {
  5. properties: {
  6. my_counter: {
  7. type: 'unsigned_long'
  8. }
  9. }
  10. }
  11. }
  12. )
  13. puts response
  1. const response = await client.indices.create({
  2. index: "my_index",
  3. mappings: {
  4. properties: {
  5. my_counter: {
  6. type: "unsigned_long",
  7. },
  8. },
  9. },
  10. });
  11. console.log(response);
  1. PUT my_index
  2. {
  3. "mappings": {
  4. "properties": {
  5. "my_counter": {
  6. "type": "unsigned_long"
  7. }
  8. }
  9. }
  10. }

Unsigned long can be indexed in a numeric or string form, representing integer values in the range [0, 18446744073709551615]. They can’t have a decimal part.

  1. resp = client.bulk(
  2. index="my_index",
  3. refresh=True,
  4. operations=[
  5. {
  6. "index": {
  7. "_id": 1
  8. }
  9. },
  10. {
  11. "my_counter": 0
  12. },
  13. {
  14. "index": {
  15. "_id": 2
  16. }
  17. },
  18. {
  19. "my_counter": 9223372036854776000
  20. },
  21. {
  22. "index": {
  23. "_id": 3
  24. }
  25. },
  26. {
  27. "my_counter": 18446744073709552000
  28. },
  29. {
  30. "index": {
  31. "_id": 4
  32. }
  33. },
  34. {
  35. "my_counter": 18446744073709552000
  36. }
  37. ],
  38. )
  39. print(resp)
  1. response = client.bulk(
  2. index: 'my_index',
  3. refresh: true,
  4. body: [
  5. {
  6. index: {
  7. _id: 1
  8. }
  9. },
  10. {
  11. my_counter: 0
  12. },
  13. {
  14. index: {
  15. _id: 2
  16. }
  17. },
  18. {
  19. my_counter: 9_223_372_036_854_776_000
  20. },
  21. {
  22. index: {
  23. _id: 3
  24. }
  25. },
  26. {
  27. my_counter: 18_446_744_073_709_552_000
  28. },
  29. {
  30. index: {
  31. _id: 4
  32. }
  33. },
  34. {
  35. my_counter: 18_446_744_073_709_552_000
  36. }
  37. ]
  38. )
  39. puts response
  1. const response = await client.bulk({
  2. index: "my_index",
  3. refresh: "true",
  4. operations: [
  5. {
  6. index: {
  7. _id: 1,
  8. },
  9. },
  10. {
  11. my_counter: 0,
  12. },
  13. {
  14. index: {
  15. _id: 2,
  16. },
  17. },
  18. {
  19. my_counter: 9223372036854776000,
  20. },
  21. {
  22. index: {
  23. _id: 3,
  24. },
  25. },
  26. {
  27. my_counter: 18446744073709552000,
  28. },
  29. {
  30. index: {
  31. _id: 4,
  32. },
  33. },
  34. {
  35. my_counter: 18446744073709552000,
  36. },
  37. ],
  38. });
  39. console.log(response);
  1. POST /my_index/_bulk?refresh
  2. {"index":{"_id":1}}
  3. {"my_counter": 0}
  4. {"index":{"_id":2}}
  5. {"my_counter": 9223372036854775808}
  6. {"index":{"_id":3}}
  7. {"my_counter": 18446744073709551614}
  8. {"index":{"_id":4}}
  9. {"my_counter": 18446744073709551615}

Term queries accept any numbers in a numeric or string form.

  1. resp = client.search(
  2. index="my_index",
  3. query={
  4. "term": {
  5. "my_counter": 18446744073709552000
  6. }
  7. },
  8. )
  9. print(resp)
  1. response = client.search(
  2. index: 'my_index',
  3. body: {
  4. query: {
  5. term: {
  6. my_counter: 18_446_744_073_709_552_000
  7. }
  8. }
  9. }
  10. )
  11. puts response
  1. const response = await client.search({
  2. index: "my_index",
  3. query: {
  4. term: {
  5. my_counter: 18446744073709552000,
  6. },
  7. },
  8. });
  9. console.log(response);
  1. GET /my_index/_search
  2. {
  3. "query": {
  4. "term" : {
  5. "my_counter" : 18446744073709551615
  6. }
  7. }
  8. }

Range query terms can contain values with decimal parts. In this case Elasticsearch converts them to integer values: gte and gt terms are converted to the nearest integer up inclusive, and lt and lte ranges are converted to the nearest integer down inclusive.

It is recommended to pass ranges as strings to ensure they are parsed without any loss of precision.

  1. resp = client.search(
  2. index="my_index",
  3. query={
  4. "range": {
  5. "my_counter": {
  6. "gte": "9223372036854775808",
  7. "lte": "18446744073709551615"
  8. }
  9. }
  10. },
  11. )
  12. print(resp)
  1. response = client.search(
  2. index: 'my_index',
  3. body: {
  4. query: {
  5. range: {
  6. my_counter: {
  7. gte: '9223372036854775808',
  8. lte: '18446744073709551615'
  9. }
  10. }
  11. }
  12. }
  13. )
  14. puts response
  1. const response = await client.search({
  2. index: "my_index",
  3. query: {
  4. range: {
  5. my_counter: {
  6. gte: "9223372036854775808",
  7. lte: "18446744073709551615",
  8. },
  9. },
  10. },
  11. });
  12. console.log(response);
  1. GET /my_index/_search
  2. {
  3. "query": {
  4. "range" : {
  5. "my_counter" : {
  6. "gte" : "9223372036854775808",
  7. "lte" : "18446744073709551615"
  8. }
  9. }
  10. }
  11. }

Sort values

For queries with sort on an unsigned_long field, for a particular document Elasticsearch returns a sort value of the type long if the value of this document is within the range of long values, or of the type BigInteger if the value exceeds this range.

REST clients need to be able to handle big integer values in JSON to support this field type correctly.

  1. resp = client.search(
  2. index="my_index",
  3. query={
  4. "match_all": {}
  5. },
  6. sort={
  7. "my_counter": "desc"
  8. },
  9. )
  10. print(resp)
  1. response = client.search(
  2. index: 'my_index',
  3. body: {
  4. query: {
  5. match_all: {}
  6. },
  7. sort: {
  8. my_counter: 'desc'
  9. }
  10. }
  11. )
  12. puts response
  1. const response = await client.search({
  2. index: "my_index",
  3. query: {
  4. match_all: {},
  5. },
  6. sort: {
  7. my_counter: "desc",
  8. },
  9. });
  10. console.log(response);
  1. GET /my_index/_search
  2. {
  3. "query": {
  4. "match_all" : {}
  5. },
  6. "sort" : {"my_counter" : "desc"}
  7. }

Stored fields

A stored field of unsigned_long is stored and returned as String.

Aggregations

For terms aggregations, similarly to sort values, Long or BigInteger values are used. For other aggregations, values are converted to the double type.

Script values

By default, script values of an unsigned_long field are returned as Java signed Long, which means that values that are greater than Long.MAX_VALUE are shown as negative values. You can use Long.compareUnsigned(long, long), Long.divideUnsigned(long, long) and Long.remainderUnsigned(long, long) to correctly work with these values.

For example, the script below returns a value of the counter divided by 10.

  1. resp = client.search(
  2. index="my_index",
  3. query={
  4. "match_all": {}
  5. },
  6. script_fields={
  7. "count10": {
  8. "script": {
  9. "source": "Long.divideUnsigned(doc['my_counter'].value, 10)"
  10. }
  11. }
  12. },
  13. )
  14. print(resp)
  1. response = client.search(
  2. index: 'my_index',
  3. body: {
  4. query: {
  5. match_all: {}
  6. },
  7. script_fields: {
  8. "count10": {
  9. script: {
  10. source: "Long.divideUnsigned(doc['my_counter'].value, 10)"
  11. }
  12. }
  13. }
  14. }
  15. )
  16. puts response
  1. const response = await client.search({
  2. index: "my_index",
  3. query: {
  4. match_all: {},
  5. },
  6. script_fields: {
  7. count10: {
  8. script: {
  9. source: "Long.divideUnsigned(doc['my_counter'].value, 10)",
  10. },
  11. },
  12. },
  13. });
  14. console.log(response);
  1. GET /my_index/_search
  2. {
  3. "query": {
  4. "match_all" : {}
  5. },
  6. "script_fields": {
  7. "count10" : {
  8. "script": {
  9. "source": "Long.divideUnsigned(doc['my_counter'].value, 10)"
  10. }
  11. }
  12. }
  13. }

Alternatively, you can treat the unsigned long type as BigInteger in your scripts by using the field API. For example, this script treats my_counter as BigInteger with a default value of BigInteger.ZERO:

  1. "script": {
  2. "source": "field('my_counter').asBigInteger(BigInteger.ZERO)"
  3. }

For scripts that need to return float or double values, you can further convert BigInteger values to double or float:

  1. resp = client.search(
  2. index="my_index",
  3. query={
  4. "script_score": {
  5. "query": {
  6. "match_all": {}
  7. },
  8. "script": {
  9. "source": "field('my_counter').asBigInteger(BigInteger.ZERO).floatValue()"
  10. }
  11. }
  12. },
  13. )
  14. print(resp)
  1. response = client.search(
  2. index: 'my_index',
  3. body: {
  4. query: {
  5. script_score: {
  6. query: {
  7. match_all: {}
  8. },
  9. script: {
  10. source: "field('my_counter').asBigInteger(BigInteger.ZERO).floatValue()"
  11. }
  12. }
  13. }
  14. }
  15. )
  16. puts response
  1. const response = await client.search({
  2. index: "my_index",
  3. query: {
  4. script_score: {
  5. query: {
  6. match_all: {},
  7. },
  8. script: {
  9. source:
  10. "field('my_counter').asBigInteger(BigInteger.ZERO).floatValue()",
  11. },
  12. },
  13. },
  14. });
  15. console.log(response);
  1. GET /my_index/_search
  2. {
  3. "query": {
  4. "script_score": {
  5. "query": {"match_all": {}},
  6. "script": {
  7. "source": "field('my_counter').asBigInteger(BigInteger.ZERO).floatValue()"
  8. }
  9. }
  10. }
  11. }

Queries with mixed numeric types

Searches with mixed numeric types one of which is unsigned_long are supported, except queries with sort. Thus, a sort query across two indexes where the same field name has an unsigned_long type in one index, and long type in another, doesn’t produce correct results and must be avoided. If there is a need for such kind of sorting, script based sorting can be used instead.

Aggregations across several numeric types one of which is unsigned_long are supported. In this case, values are converted to the double type.