influxdata / influxdb-python

Python client for InfluxDB
MIT License
1.69k stars 520 forks source link

InfluxDBClientError: 400 ("error":"partial write: field type conflict) #572

Open supriyopaul opened 6 years ago

supriyopaul commented 6 years ago

According to influxdb doc : " by default, InfluxDB assumes all numerical field values are floats."

> INSERT weather,location=us-midwest temperature=82 1465839830100400200
> show field keys from weather
name: weather
fieldKey    fieldType
--------    ---------
temperature float

But InfluxDBClient module for python: It does not do the same.

>>> from influxdb import InfluxDBClient

>>> json_body = [{"measurement": "cpu_load_short","tags": {"host": "server01","region": "us-west"},"time": "2009-11-10T23:00:00Z","fields": {"value": 82}}]

>>> client = InfluxDBClient('localhost', 8086, 'root', 'root', 'example')
>>> client.create_database('example')
>>> client.write_points(json_body)
True
>>> 
[supriyo][05:59 PM][~]$ influx
Connected to http://localhost:8086 version 1.5.0
InfluxDB shell version: 1.5.0
> show databases
name: databases
name
----
_internal
logs
example
> use example
Using database example
> show measurements
name: measurements
name
----
cpu_load_short
> show field keys from cpu_load_short
name: cpu_load_short
fieldKey fieldType
-------- ---------
value    integer
> 

image

Now the concern is what if the programs change the data-types while using the InfluxdbClient? Points won't get written into database...

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/influxdb/client.py", line 456, in write_points
    tags=tags, protocol=protocol)
  File "/usr/local/lib/python2.7/dist-packages/influxdb/client.py", line 506, in _write_points
    protocol=protocol
  File "/usr/local/lib/python2.7/dist-packages/influxdb/client.py", line 302, in write
    headers=headers
  File "/usr/local/lib/python2.7/dist-packages/influxdb/client.py", line 263, in request
    raise InfluxDBClientError(response.content, response.status_code)
influxdb.exceptions.InfluxDBClientError: 400: {"error":"partial write: field type conflict: input field \"value\" on 
measurement \"test\" is type integer, already exists as type float dropped=1"}
ayoube01 commented 6 years ago

did you get to solve the issues ? thanks

supriyopaul commented 6 years ago

@ayoube01 after a while I realized InfluxDBClient is doing the expected thing. It conveys python datatypes to influxDB without any intelligent decision making of assumptions.

tux-00 commented 6 years ago

@ayoube01 @supriyopaul the temporary solution I used to convert int to float:

def df_int_to_float(df):
    for i in df.select_dtypes('int').columns.values:
        df[i] = df[i].astype(float)
    return df

df = self.df_int_to_float(df)
supriyopaul commented 6 years ago

@tux-00 Thanks, I too did the same.

zsyh commented 5 years ago

If you assume all numerical field values are floats, try following code. It uses monkey patch to remove + "i" code when type is integer.

import influxdb
from influxdb import InfluxDBClient
from influxdb.line_protocol import _get_unicode, quote_ident, _is_float, text_type

class MyInfluxDBClient(InfluxDBClient):
    def __init__(self, host='localhost', port=8086, username='root', password='root', database=None, ssl=False,
                 verify_ssl=False, timeout=None, retries=3, use_udp=False, udp_port=4444, proxies=None, pool_size=10,
                 path=''):
        super().__init__(host, port, username, password, database, ssl, verify_ssl, timeout, retries, use_udp, udp_port,
                         proxies, pool_size, path)

        # monkey patch, no integer
        def _escape_value(value):
            value = _get_unicode(value)

            if isinstance(value, text_type) and value != '':
                return quote_ident(value)
            elif _is_float(value):
                return repr(value)

            return str(value)
        influxdb.line_protocol._escape_value = _escape_value
webmaniak commented 4 years ago

In the end, shouldn't the Python module do the conversion itself?

I mean, if by default InfluxDB considers all int values to be float (unless told explicitely with the "i" character placed after the intvalue), then why both InfluxDbClient and its subclasses do not enforce this rule automatically by converting values like @tux-00 suggested?