{ "info": { "author": "Winton Wang", "author_email": "365504029@qq.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved", "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3 :: Only", "Topic :: Software Development", "Topic :: Software Development :: Libraries" ], "description": "=========\nTT-series\n=========\n\nHigh performance engine to store Time series data in Redis.\n\n|travis| |appveyor| |codecov| |codacy| |requirements| |docs| |pypi| |status| |pyversion|\n\n\nTT-series is based on redis sorted sets to store the time-series data, `Sorted set`_ store scores with\nunique numbers under a single key, but it has a weakness to store records, only unique members are allowed\nand trying to record a time-series entry with the same value as a previous will result in only updating the score.\nSo TT-series provide a solution to solve that problem.\n\nTT series normally can support redis version > 3.0, and will support **redis 5.0** in the future.\n\nTips\n====\n\n- **Max Store series length**\n\n For 32 bit Redis on a 32 bit platform redis sorted sets can support maximum 2**32-1 members,\n and for 64 bit redis on a 64 bit platform can support maximum 2**64-1 members.\n But large amount of data would cause more CPU activity, so better keep a balance with length of records is\n very important.\n\n- **Only Support Python 3.6**\n\n Because python 3.6 changed the dictionary implementation for better performance,\n so in Python 3.6 dictionaries are insertion ordered.\n links: https://stackoverflow.com/questions/39980323/are-dictionaries-ordered-in-python-3-6\n\n- **Performance Tips**\n\n With hiredis-py which it's targeted at speeding up parsing multi bulk replies from redis-server.\n So with a large amount of bulk data insertion or getting from redis-server, it can improve a great performance improvement.\n\nInstall\n=======\n\nInstall python package from pip release::\n\n pip install ttseries\n\n\nDocumentation\n=============\n\nFeatures\n--------\n\n1. Quick inserts 100,000 records (1-2 sec) and get slice of 100,000 records (0.4-0.5 sec).\n\n2. Support Data Serializer, Default Enable with MessagePack.\n\n3. Support Data Compression.\n\n4. In-order to void update previous records, Support Redis Hashes Time-Series storage format.\n\n5. Support Numpy ndarray data type.\n\n5. Support max length to auto to trim records.\n\n\nUsage\n-----\n\n\nTT-series provide three implementation to support different kinds of time-series data type.\n\n- ``RedisSimpleTimeSeries`` : Normally only base on Sorted sets to store records, previous records will impact the new inserting records which are **NOT** unique numbers.\n\n- ``RedisHashTimeSeries``: Use Redis Sorted sets with Hashes to store time-series data, User don't need to consider the data repeatability with records, but sorted sets with hashes would take some extra memories to store the keys.\n\n- ``RedisNumpyTimeSeries``: Support ``numpy.ndarray`` to store time-series records in redis sorted set.\n\n- ``RedisPandasTimeSeries``: Support ``pandas.DataFrame`` to store time-series records in redis sorted set.\n\nSerializer Data\n---------------\n\nTT-series use `MsgPack`_ to serializer data, because compare with other data serializer's solutions,\nMsgPack provide a better performance solution to serialize data. If user don't want to use MsgPack to\nserializer data, just inherit from ``ttseries.BaseSerializer`` class to implement the supported\nserializer class methods.\n\nExamples\n--------\n\n``RedisSimpleTimeSeries`` && ``RedisHashTimeSeries`` && ``RedisNumpyTimeSeries`` && ``RedisPandasTimeSeries``\n\nThree series data implementation provide the same functions and methods, in the usage will\nprovide the difference in the methods.\n\nPrepare data records:\n^^^^^^^^^^^^^^^^^^^^^\n\n.. sourcecode:: python\n\n from datetime import datetime\n from redis import StrictRedis\n\n now = datetime.now()\n timestamp = now.timestamp()\n\n series_data = []\n\n for i in range(1000):\n series_data.append((timestamp+i,i))\n\n client = StrictRedis() # redis client\n\n\nAdd records\n^^^^^^^^^^^\n\n.. sourcecode:: python\n\n from ttseries import RedisSimpleTimeSeries\n\n simple_series = RedisSimpleTimeSeries(client=client)\n\n key = \"TEST:SIMPLE\"\n\n simple_series.add_many(key, series_data)\n\n\n\nCount records length\n^^^^^^^^^^^^^^^^^^^^\n\nGet the length of the records or need just get the length from timestamp span.\n\n.. sourcecode:: python\n\n # get the records length\n simple_series.length(key)\n\n # result: ...: 1000\n\n # get the records length from start timestamp and end timestamp\n simple_series.count(key, from_timestamp=timestamp, end_timestamp=timestamp+10)\n\n # result: ...: 11\n\n\ntrim records\n^^^^^^^^^^^^\n\nTrim the records as the ASC.\n\n.. sourcecode:: python\n\n simple_series.trim(key,10) # trim 10 length of records\n\n\ndelete timestamp span\n^^^^^^^^^^^^^^^^^^^^^\n\nDelete timestamp provide delete key or delete records from start timestamp to end timestamp.\n\n.. sourcecode:: python\n\n simple_series.delete(key) # delete key with all records\n\n simple_series.delete(key, start_timestamp=timestamp) # delete key form start timestamp\n\n\nGet Slice\n^^^^^^^^^\n\nGet slice form records provide start timestamp and end timestamp with **ASC** or **DESC** ordered.\n\nDefault Order: **ASC**\n\nIf user want to get the timestamp great than (>) or less than (<) which not including the timestamp record.\njust use ``(timestamp`` which support ``timestamp`` sign format like this.\n\n.. sourcecode:: python\n\n # get series data from start timestamp ordered as ASC.\n\n simple_series.get_slice(key, start_timestamp=timestamp, acs=True)\n\n # get series data from great than start timestamp order as ASC\n simple_series.get_slice(key, start_timestamp=\"(\"+str(timestamp), asc=True)\n\n # get series data from start timestamp and limit the numbers with 500\n time_series.get_slice(key,start_timestamp=timestamp,limit=500)\n\n\niter\n^^^^\n\nyield item from records.\n\n.. sourcecode:: python\n\n for item in simple_series.iter(key):\n print(item)\n\n\n\nRedisNumpyTimeSeries\n^^^^^^^^^^^^^^^^^^^^\n\nNumpy array support provide ``numpy.dtype`` or just arrays with data.\n\nUse ``numpy.dtype`` to create records. must provide ``timestamp_column_name`` and ``dtype`` parameters.\n\n.. sourcecode:: python\n\n import numpy as np\n from ttseries import RedisNumpyTimeSeries\n\n dtype = [(\"timestamp\",\"float64\"),(\"value\",\"i\")]\n\n array = np.array(series_data, dtype=dtype)\n\n np_series = RedisNumpyTimeSeries(client=client, dtype=dtype, timestamp_column_name=\"timestamp\")\n\n\nOr just numpy array without dtype, but must provide ``timestamp_column_index`` parameter.\n\n.. sourcecode:: python\n\n array = np.array(series_data)\n\n np_series = RedisNumpyTimeSeries(client=client,timestamp_column_index=0)\n\n\nRedisPandasTimeSeries\n^^^^^^^^^^^^^^^^^^^^^\n\nPandas TimeSeries use ``pandas.DataFrame`` to store time-series in redis.\nTo initialize the class must provide ``columns`` and ``dtypes`` parameters.\n\n1. ``columns`` parameter indicates the column names of the ``pandas.DataFrame``.\n\n2. ``dtypes`` indicates the dtype of each column in DataFrame, for example: ``{ \"value1\":\"int64\",\"value2\":\"float32\"}``\n reference link: http://pbpython.com/pandas_dtypes.html\n\n.. sourcecode:: python\n\n from datetime import datetime\n\n key = \"AA:MIN\"\n now = datetime.now()\n columns = [\"value\"]\n date_range = pandas.date_range(now, periods=10, freq=\"1min\")\n\n data_frame = pandas.DataFrame([i + 1 for i in range(len(date_range))],\n index=date_range, columns=columns)\n\n\n dtypes = {\"value\":\"int64\"}\n pandas_ts = RedisPandasTimeSeries(client=client, columns=columns, dtypes=dtypes)\n\nAdd\n^^^\n\nAdd a time-series record to redis, ``series`` parameter indicates ``pandas.Series`` data type.\nand especial the ``series`` name value data type must be the ``pandas.DatetimeIndex``.\n\n.. sourcecode:: python\n\n series_item = data_frame.iloc[0]\n pandas_ts.add(key, series_item)\n\n\nadd_many\n^^^^^^^^\n\nAdd large amount of ``pandas.DataFrame`` into redis, with the ``dataframe`` index data type must be\nthe ``pandas.DatetimeIndex``.\nFor better insert performance, just use ``chunks_size`` to split the dataframe into fixed ``chunks_size``\nrows of dataframes.\n\n.. sourcecode:: python\n\n pandas_ts.add_many(key, data_frame)\n\n\niter & Get\n^^^^^^^^^^\n\nretrieve records from redis sorted set, both of methods return ``pandas.Series``.\n\n.. sourcecode:: python\n\n # yield all records data from redis\n for item in pandas_ts.iter(key):\n print(item)\n # return one record with specific timestamp\n pandas_ts.get(key, 1536157765.464465)\n\nget_slice\n^^^^^^^^^\n\nretrieve records to slice with ``start timestamp`` or ``end timestamp``, with ``limit`` length.\nreturn ``pandas.DataFrame``\n\n.. sourcecode:: python\n\n # return records from start timestamp 1536157765.464465\n result_frame = pandas_ts.get_slice(key, start_timestamp=1536157765.464465)\n\n # return records from start timestamp 1536157765.464465 to end timestamp 1536157780.464465\n result2_frame = padas_ts.get_slice(key, start_timestamp=1536157765.464465, end_timestamp=1536157780.464465)\n\n\nBenchmark\n=========\n\njust run ``make benchmark-init``, after then start ``make benchmark-test``.\n\nGo to the benchmark directory there exist an example of the benchmark test reports.\n\n\nTODO\n====\n\n1. Support Redis 5.0\n\n3. Support Redis cluster.\n\n\nAuthor\n======\n\n- Winton Wang\n\n\nDonate\n======\n\n\nContact\n=======\n\nEmail: 365504029@qq.com\n\n\nReference\n=========\n\nlinks: https://www.infoq.com/articles/redis-time-series\n\n\n.. _Sorted set: https://redis.io/commands#sorted_set\n.. _MsgPack: http://msgpack.org\n\n.. |travis| image:: https://travis-ci.org/nooperpudd/ttseries.svg?branch=master\n :target: https://travis-ci.org/nooperpudd/ttseries\n\n.. |appveyor| image:: https://ci.appveyor.com/api/projects/status/ntlhwaagr5dqh341/branch/master?svg=true\n :target: https://ci.appveyor.com/project/nooperpudd/ttseries\n\n.. |codecov| image:: https://codecov.io/gh/nooperpudd/ttseries/branch/master/graph/badge.svg\n :target: https://codecov.io/gh/nooperpudd/ttseries\n\n.. |codacy| image:: https://api.codacy.com/project/badge/Grade/154fe60c6d2b4e59b8ee18baa56ad0a9\n :target: https://www.codacy.com/app/nooperpudd/ttseries?utm_source=github.com&utm_medium=referral&utm_content=nooperpudd/ttseries&utm_campaign=Badge_Grade\n\n.. |pypi| image:: https://img.shields.io/pypi/v/ttseries.svg\n :target: https://pypi.python.org/pypi/ttseries\n\n.. |status| image:: https://img.shields.io/pypi/status/ttseries.svg\n :target: https://pypi.python.org/pypi/ttseries\n\n.. |pyversion| image:: https://img.shields.io/pypi/pyversions/ttseries.svg\n :target: https://pypi.python.org/pypi/ttseries\n\n.. |requirements| image:: https://requires.io/github/nooperpudd/ttseries/requirements.svg?branch=master\n :target: https://requires.io/github/nooperpudd/ttseries/requirements/?branch=master\n\n.. |docs| image:: https://readthedocs.org/projects/ttseries/badge/?version=latest\n :target: http://ttseries.readthedocs.io/en/latest/?badge=latest", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/nooperpudd/ttseries", "keywords": "Time Series,Redis Time Series", "license": "LGPLv3", "maintainer": "", "maintainer_email": "", "name": "ttseries", "package_url": "https://pypi.org/project/ttseries/", "platform": "any", "project_url": "https://pypi.org/project/ttseries/", "project_urls": { "Homepage": "https://github.com/nooperpudd/ttseries" }, "release_url": "https://pypi.org/project/ttseries/0.2.1/", "requires_dist": null, "requires_python": ">=3.6", "summary": "Time series data store in Redis", "version": "0.2.1" }, "last_serial": 5175979, "releases": { "0.1.3": [ { "comment_text": "", "digests": { "md5": "c24d011c0de5df5513a25f73aa7d32d7", "sha256": "b35177553d5a699c970ce063fb557ea3ad1c467576dfc2b33da2e122c913a530" }, "downloads": -1, "filename": "ttseries-0.1.3.tar.gz", "has_sig": false, "md5_digest": "c24d011c0de5df5513a25f73aa7d32d7", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 17124, "upload_time": "2018-06-03T14:27:52", "url": "https://files.pythonhosted.org/packages/7f/8b/409b861112ab506c28d6a219fb942ec064584666ae924e6e6e5faaf901f2/ttseries-0.1.3.tar.gz" } ], "0.1.7": [ { "comment_text": "", "digests": { "md5": "faecd131fa81d8bf78b8cbc03e62c7b2", "sha256": "0c1a971b4129a1744bdaba3980b6c4c134c7c2a53407c86c0485c9b62443c633" }, "downloads": -1, "filename": "ttseries-0.1.7.tar.gz", "has_sig": false, "md5_digest": "faecd131fa81d8bf78b8cbc03e62c7b2", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 25270, "upload_time": "2018-09-05T15:09:40", "url": "https://files.pythonhosted.org/packages/a6/48/02be996fec353fee6acf964edaf151cfad61da2a218c4909d721848fc62c/ttseries-0.1.7.tar.gz" } ], "0.1.8": [ { "comment_text": "", "digests": { "md5": "c8f8ed485ff8a3c300c467a316000a51", "sha256": "6afc6fb9ec771bf8f8c52160802b8db31ebe9d055bca493ffd05cb750ea71486" }, "downloads": -1, "filename": "ttseries-0.1.8.tar.gz", "has_sig": false, "md5_digest": "c8f8ed485ff8a3c300c467a316000a51", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 20812, "upload_time": "2018-09-18T14:42:10", "url": "https://files.pythonhosted.org/packages/70/05/d902e54a18a3ee201857d6c69bb2cc6ac4299cfa0cc37a09a02f553cfd4b/ttseries-0.1.8.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "e39edbba7f95fe65463e4a02287018ce", "sha256": "b60cdadea757e80ff7660e59938c9982848367aa510ed9bc8d7cccf8f2a49c54" }, "downloads": -1, "filename": "ttseries-0.2.0.tar.gz", "has_sig": false, "md5_digest": "e39edbba7f95fe65463e4a02287018ce", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 20717, "upload_time": "2019-02-09T06:41:19", "url": "https://files.pythonhosted.org/packages/2b/a4/ac3dbd9323324606e95d449ac1442573be63b4dc358b4d9b11fb48ac563f/ttseries-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "cf9f6bd47ace71bec50d123d5c1ed853", "sha256": "5f03879fe3631973f4c92c50d3167682f6011655a95a718b17357d34eabdca63" }, "downloads": -1, "filename": "ttseries-0.2.1.tar.gz", "has_sig": false, "md5_digest": "cf9f6bd47ace71bec50d123d5c1ed853", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 20371, "upload_time": "2019-04-23T08:18:11", "url": "https://files.pythonhosted.org/packages/40/11/a52f10a952dd51e2d308002cf9294c404d008257335cc02fe567777388ad/ttseries-0.2.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "cf9f6bd47ace71bec50d123d5c1ed853", "sha256": "5f03879fe3631973f4c92c50d3167682f6011655a95a718b17357d34eabdca63" }, "downloads": -1, "filename": "ttseries-0.2.1.tar.gz", "has_sig": false, "md5_digest": "cf9f6bd47ace71bec50d123d5c1ed853", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 20371, "upload_time": "2019-04-23T08:18:11", "url": "https://files.pythonhosted.org/packages/40/11/a52f10a952dd51e2d308002cf9294c404d008257335cc02fe567777388ad/ttseries-0.2.1.tar.gz" } ] }