├── .gitignore ├── images ├── mindsdb_web_console.png └── questdb_web_console.png ├── Dockerfile ├── sample_house_rentals_data.csv ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | mindsdb_store/ 3 | nltk_data/ 4 | qdb_root/ 5 | .DS_Store/ 6 | -------------------------------------------------------------------------------- /images/mindsdb_web_console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/questdb/mindsdb-tutorial/HEAD/images/mindsdb_web_console.png -------------------------------------------------------------------------------- /images/questdb_web_console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/questdb/mindsdb-tutorial/HEAD/images/questdb_web_console.png -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10-slim-buster 2 | 3 | # cat /etc/os-release 4 | # Debian GNU/Linux 11 (bullseye) 5 | # TCP ports: 6 | # - 9000: QuestDB Web Console 7 | # - 8812: QuestDB pg-wire 8 | # - 9009: QuestDB ILP ingress line protocol 9 | # - 47334: MindsDB WebConsole 10 | # - 47335: MindsDB mysql API 11 | # - 47336: MindsDB mongodb API 12 | 13 | EXPOSE 8812/tcp 14 | EXPOSE 9000/tcp 15 | EXPOSE 9009/tcp 16 | EXPOSE 47334/tcp 17 | EXPOSE 47335/tcp 18 | EXPOSE 47336/tcp 19 | 20 | ENV JDK_VERSION=17.0.7.7-1 21 | ENV FLASK_DEBUG "1" 22 | 23 | # Update system - Install JDK 17 24 | RUN apt-get -y update 25 | RUN apt-get -y dist-upgrade 26 | RUN apt-get -y install software-properties-common build-essential syslog-ng \ 27 | ca-certificates gnupg2 lsb-release iputils-ping procps git curl wget vim \ 28 | unzip less tar gzip bzip2 openssl lshw libxml2 net-tools 29 | RUN wget -O- https://apt.corretto.aws/corretto.key | gpg --dearmor | tee /etc/apt/trusted.gpg.d/winehq.gpg >/dev/null && \ 30 | add-apt-repository 'deb https://apt.corretto.aws stable main' && \ 31 | apt-get update && \ 32 | apt-get install --no-install-recommends -y java-17-amazon-corretto-jdk=1:${JDK_VERSION} && \ 33 | apt-get -y install maven 34 | RUN apt-get clean 35 | RUN rm -rf /var/lib/apt/lists/* 36 | 37 | # Create new user 'quest' - user and workdir 38 | RUN useradd -ms /bin/bash quest 39 | USER quest 40 | WORKDIR /home/quest 41 | ENV QUESTDB_TAG=7.3.1 42 | ENV PYTHONUNBUFFERED 1 43 | ENV JAVA_HOME=/usr/lib/jvm/java-17-amazon-corretto 44 | ENV PATH="${JAVA_HOME}/bin:/home/quest/.local/bin:${PATH}" 45 | RUN echo "alias l='ls -l'" >> ~/.bashrc 46 | RUN echo "alias ll='ls -la'" >> ~/.bashrc 47 | RUN echo "alias rm='rm -i'" >> ~/.bashrc 48 | 49 | # Install/Configure QuestDB 50 | RUN echo tag_name ${QUESTDB_TAG} 51 | RUN curl -L -o questdb.tar.gz "https://github.com/questdb/questdb/releases/download/${QUESTDB_TAG}/questdb-${QUESTDB_TAG}-no-jre-bin.tar.gz" 52 | RUN tar xvfz questdb.tar.gz 53 | RUN rm questdb.tar.gz 54 | RUN mv "questdb-${QUESTDB_TAG}-no-jre-bin" questdb 55 | RUN mkdir csv 56 | RUN mkdir tmp 57 | RUN mkdir backups 58 | RUN mkdir questdb/db 59 | RUN mkdir questdb/conf 60 | RUN echo "config.validation.strict=true" > questdb/conf/server.conf 61 | RUN echo "query.timeout.sec=120" >> questdb/conf/server.conf 62 | RUN echo "cairo.sql.copy.root=/home/quest/csv" >> questdb/conf/server.conf 63 | RUN echo "cairo.sql.copy.work.root=/home/quest/tmp" >> questdb/conf/server.conf 64 | RUN echo "cairo.sql.backup.root=/home/quest/backups" >> questdb/conf/server.conf 65 | RUN ulimit -S unlimited 66 | RUN ulimit -H unlimited 67 | 68 | # Install requirements for datascience environment 69 | RUN pip install --upgrade pip 70 | RUN pip install pandas matplotlib seaborn psycopg2-binary boto3 neuralforecast questdb mindsdb 71 | RUN python3 -c 'import nltk; nltk.download("punkt");' 72 | RUN pip install numpy --upgrade 73 | 74 | # Configure MindsDB 75 | RUN mkdir mindsdb 76 | RUN mkdir mindsdb/storage 77 | RUN echo '{' > conf.json 78 | RUN echo ' "config_version":"1.4",' >> conf.json 79 | RUN echo ' "storage_dir": "/home/quest/mindsdb/storage",' >> conf.json 80 | RUN echo ' "log": {' >> conf.json 81 | RUN echo ' "level": {' >> conf.json 82 | RUN echo ' "console": "ERROR",' >> conf.json 83 | RUN echo ' "file": "WARNING",' >> conf.json 84 | RUN echo ' "db": "WARNING"' >> conf.json 85 | RUN echo ' }' >> conf.json 86 | RUN echo ' },' >> conf.json 87 | RUN echo ' "debug": false,' >> conf.json 88 | RUN echo ' "integrations": {},' >> conf.json 89 | RUN echo ' "api": {' >> conf.json 90 | RUN echo ' "http": {' >> conf.json 91 | RUN echo ' "host": "0.0.0.0",' >> conf.json 92 | RUN echo ' "port": "47334"' >> conf.json 93 | RUN echo ' },' >> conf.json 94 | RUN echo ' "mysql": {' >> conf.json 95 | RUN echo ' "host": "0.0.0.0",' >> conf.json 96 | RUN echo ' "password": "",' >> conf.json 97 | RUN echo ' "port": "47335",' >> conf.json 98 | RUN echo ' "user": "mindsdb",' >> conf.json 99 | RUN echo ' "database": "mindsdb",' >> conf.json 100 | RUN echo ' "ssl": true' >> conf.json 101 | RUN echo ' },' >> conf.json 102 | RUN echo ' "mongodb": {' >> conf.json 103 | RUN echo ' "host": "0.0.0.0",' >> conf.json 104 | RUN echo ' "port": "47336",' >> conf.json 105 | RUN echo ' "database": "mindsdb"' >> conf.json 106 | RUN echo ' }' >> conf.json 107 | RUN echo ' }' >> conf.json 108 | RUN echo '}' >> conf.json 109 | RUN mv conf.json mindsdb/mindsdb_config.json 110 | 111 | # Prepare run script 112 | RUN echo "#!/bin/bash" > run.sh 113 | RUN echo "/home/quest/questdb/questdb.sh start -d /home/quest/questdb" >> run.sh 114 | RUN echo "python -m mindsdb --config=/home/quest/mindsdb/mindsdb_config.json --api=http,mysql,mongodb" >> run.sh 115 | RUN chmod 700 run.sh 116 | 117 | CMD ["/bin/bash", "-c", "/home/quest/run.sh"] 118 | -------------------------------------------------------------------------------- /sample_house_rentals_data.csv: -------------------------------------------------------------------------------- 1 | "number_of_rooms","number_of_bathrooms","sqft","location","days_on_market","initial_price","neighborhood","rental_price","ts" 2 | 5,1,1786,"good",12,320.3779,"downtown",701.2380,"2021-01-01T00:00:00.000000Z" 3 | 3,3,1601,"poor",3,25.4468,"south_side",911.0829,"2021-01-01T04:00:00.000000Z" 4 | 3,1,1072,"poor",12,358.9587,"berkeley_hills",1331.1584,"2021-01-01T08:00:00.000000Z" 5 | 6,1,718,"poor",12,385.8091,"berkeley_hills",626.7317,"2021-01-01T12:00:00.000000Z" 6 | 3,3,266,"great",19,339.5094,"downtown",1452.2515,"2021-01-01T16:00:00.000000Z" 7 | 2,2,405,"good",5,442.0967,"south_side",1366.0007,"2021-01-01T20:00:00.000000Z" 8 | 3,3,1386,"great",6,149.5398,"south_side",1398.1394,"2021-01-02T00:00:00.000000Z" 9 | 6,2,358,"poor",18,119.8078,"downtown",1063.6824,"2021-01-02T04:00:00.000000Z" 10 | 2,3,1414,"poor",20,253.9078,"thowsand_oaks",890.4299,"2021-01-02T08:00:00.000000Z" 11 | 5,2,1660,"good",19,713.4162,"berkeley_hills",540.1946,"2021-01-02T12:00:00.000000Z" 12 | 4,2,439,"poor",20,970.9116,"alcatraz_ave",957.7701,"2021-01-02T16:00:00.000000Z" 13 | 4,3,1431,"great",4,732.9635,"south_side",553.6955,"2021-01-02T20:00:00.000000Z" 14 | 4,1,1472,"good",13,111.9622,"alcatraz_ave",621.2754,"2021-01-03T00:00:00.000000Z" 15 | 2,3,968,"great",9,778.9232,"alcatraz_ave",1351.8469,"2021-01-03T04:00:00.000000Z" 16 | 3,3,1155,"good",14,856.2826,"thowsand_oaks",1341.3767,"2021-01-03T08:00:00.000000Z" 17 | 4,1,572,"good",19,865.9290,"south_side",969.6509,"2021-01-03T12:00:00.000000Z" 18 | 2,1,328,"poor",17,597.6621,"alcatraz_ave",912.4672,"2021-01-03T16:00:00.000000Z" 19 | 3,1,1805,"poor",12,27.9799,"south_side",1309.2059,"2021-01-03T20:00:00.000000Z" 20 | 3,1,604,"good",3,820.9493,"downtown",599.2306,"2021-01-04T00:00:00.000000Z" 21 | 1,2,1271,"poor",5,465.0764,"berkeley_hills",735.4945,"2021-01-04T04:00:00.000000Z" 22 | 2,1,280,"poor",6,218.2908,"westbrae",1264.8096,"2021-01-04T08:00:00.000000Z" 23 | 6,2,334,"good",13,603.5421,"south_side",825.3587,"2021-01-04T12:00:00.000000Z" 24 | 5,3,444,"great",18,826.7342,"berkeley_hills",959.1534,"2021-01-04T16:00:00.000000Z" 25 | 6,2,599,"good",14,477.7542,"alcatraz_ave",555.7320,"2021-01-04T20:00:00.000000Z" 26 | 4,3,924,"good",6,38.5340,"alcatraz_ave",1433.9055,"2021-01-05T00:00:00.000000Z" 27 | 3,3,1103,"good",15,178.7477,"berkeley_hills",783.8623,"2021-01-05T04:00:00.000000Z" 28 | 2,3,1994,"good",17,330.0997,"berkeley_hills",1443.3940,"2021-01-05T08:00:00.000000Z" 29 | 4,1,1054,"good",12,628.9840,"alcatraz_ave",510.8960,"2021-01-05T12:00:00.000000Z" 30 | 2,1,1448,"poor",17,87.6381,"alcatraz_ave",1243.7915,"2021-01-05T16:00:00.000000Z" 31 | 4,2,284,"good",15,448.8006,"thowsand_oaks",539.7591,"2021-01-05T20:00:00.000000Z" 32 | 1,2,734,"poor",10,467.6645,"downtown",1379.4719,"2021-01-06T00:00:00.000000Z" 33 | 1,2,1066,"great",15,720.6578,"downtown",1062.6108,"2021-01-06T04:00:00.000000Z" 34 | 2,3,1521,"good",1,893.5995,"westbrae",980.0384,"2021-01-06T08:00:00.000000Z" 35 | 6,2,607,"great",10,289.0917,"alcatraz_ave",1296.1814,"2021-01-06T12:00:00.000000Z" 36 | 5,1,1545,"great",13,713.7558,"alcatraz_ave",1254.9475,"2021-01-06T16:00:00.000000Z" 37 | 2,2,1669,"great",7,333.8866,"westbrae",1106.0117,"2021-01-06T20:00:00.000000Z" 38 | 6,1,576,"good",15,605.5022,"westbrae",751.8026,"2021-01-07T00:00:00.000000Z" 39 | 6,1,1654,"great",18,113.8315,"alcatraz_ave",1360.5935,"2021-01-07T04:00:00.000000Z" 40 | 5,1,225,"poor",7,407.2787,"south_side",1333.4656,"2021-01-07T08:00:00.000000Z" 41 | 5,2,590,"poor",8,670.2425,"berkeley_hills",1232.2976,"2021-01-07T12:00:00.000000Z" 42 | 3,2,1326,"good",7,416.5889,"south_side",868.2089,"2021-01-07T16:00:00.000000Z" 43 | 1,2,961,"good",19,681.2173,"westbrae",1048.9446,"2021-01-07T20:00:00.000000Z" 44 | 1,3,1106,"great",19,670.1945,"south_side",1285.3381,"2021-01-08T00:00:00.000000Z" 45 | 6,1,1368,"poor",7,964.2658,"downtown",1047.1396,"2021-01-08T04:00:00.000000Z" 46 | 5,1,1801,"good",17,803.3566,"berkeley_hills",727.5199,"2021-01-08T08:00:00.000000Z" 47 | 1,2,367,"poor",20,906.5422,"westbrae",1038.3582,"2021-01-08T12:00:00.000000Z" 48 | 6,2,1641,"good",16,556.2764,"westbrae",1047.3420,"2021-01-08T16:00:00.000000Z" 49 | 3,3,753,"good",5,606.8880,"thowsand_oaks",1067.3186,"2021-01-08T20:00:00.000000Z" 50 | 2,3,1907,"great",3,736.2479,"alcatraz_ave",1250.4768,"2021-01-09T00:00:00.000000Z" 51 | 3,2,355,"great",11,780.1654,"alcatraz_ave",653.9242,"2021-01-09T04:00:00.000000Z" 52 | 5,3,1655,"great",5,881.7164,"downtown",546.7981,"2021-01-09T08:00:00.000000Z" 53 | 3,2,696,"great",11,631.8957,"downtown",643.2042,"2021-01-09T12:00:00.000000Z" 54 | 4,1,441,"good",10,561.4860,"south_side",694.4032,"2021-01-09T16:00:00.000000Z" 55 | 3,2,1509,"poor",4,391.0188,"berkeley_hills",1256.4904,"2021-01-09T20:00:00.000000Z" 56 | 5,2,1746,"good",9,83.5649,"downtown",1357.9159,"2021-01-10T00:00:00.000000Z" 57 | 3,3,343,"good",1,810.4063,"westbrae",897.6411,"2021-01-10T04:00:00.000000Z" 58 | 1,1,1330,"poor",15,431.0702,"thowsand_oaks",1033.4163,"2021-01-10T08:00:00.000000Z" 59 | 1,2,302,"poor",15,720.4748,"downtown",1025.5692,"2021-01-10T12:00:00.000000Z" 60 | 6,1,847,"poor",15,324.8886,"thowsand_oaks",762.5094,"2021-01-10T16:00:00.000000Z" 61 | 3,3,396,"good",2,660.4577,"alcatraz_ave",1195.2478,"2021-01-10T20:00:00.000000Z" 62 | 6,1,587,"great",8,674.8561,"thowsand_oaks",1289.7607,"2021-01-11T00:00:00.000000Z" 63 | 1,3,235,"great",16,169.7373,"south_side",1394.8590,"2021-01-11T04:00:00.000000Z" 64 | 6,1,721,"great",4,958.9706,"thowsand_oaks",810.2053,"2021-01-11T08:00:00.000000Z" 65 | 6,2,843,"good",16,382.5743,"south_side",1079.8484,"2021-01-11T12:00:00.000000Z" 66 | 2,3,817,"poor",6,467.6300,"thowsand_oaks",785.3109,"2021-01-11T16:00:00.000000Z" 67 | 4,1,827,"great",13,98.5236,"berkeley_hills",858.5861,"2021-01-11T20:00:00.000000Z" 68 | 4,3,1538,"poor",3,883.3510,"thowsand_oaks",1387.4851,"2021-01-12T00:00:00.000000Z" 69 | 5,2,198,"great",3,288.8748,"berkeley_hills",514.8307,"2021-01-12T04:00:00.000000Z" 70 | 4,1,687,"good",3,396.5924,"south_side",1468.8423,"2021-01-12T08:00:00.000000Z" 71 | 1,3,207,"great",2,689.6042,"thowsand_oaks",897.6376,"2021-01-12T12:00:00.000000Z" 72 | 4,1,969,"great",1,970.5560,"berkeley_hills",584.3826,"2021-01-12T16:00:00.000000Z" 73 | 3,1,329,"good",20,305.8042,"berkeley_hills",556.4019,"2021-01-12T20:00:00.000000Z" 74 | 5,2,519,"great",20,88.1737,"south_side",948.8557,"2021-01-13T00:00:00.000000Z" 75 | 6,3,726,"great",16,450.5123,"berkeley_hills",1154.1095,"2021-01-13T04:00:00.000000Z" 76 | 6,3,672,"great",16,519.9495,"thowsand_oaks",918.4754,"2021-01-13T08:00:00.000000Z" 77 | 5,3,830,"great",17,88.2635,"alcatraz_ave",1157.3918,"2021-01-13T12:00:00.000000Z" 78 | 1,2,1833,"good",20,674.6903,"westbrae",850.4075,"2021-01-13T16:00:00.000000Z" 79 | 6,1,1570,"poor",4,209.1303,"south_side",1279.7229,"2021-01-13T20:00:00.000000Z" 80 | 2,2,1717,"poor",15,41.8065,"alcatraz_ave",1224.7593,"2021-01-14T00:00:00.000000Z" 81 | 4,3,1756,"great",1,106.8451,"south_side",1445.8887,"2021-01-14T04:00:00.000000Z" 82 | 4,1,1445,"poor",11,254.5955,"thowsand_oaks",995.2943,"2021-01-14T08:00:00.000000Z" 83 | 6,1,1909,"poor",7,515.2731,"berkeley_hills",789.0384,"2021-01-14T12:00:00.000000Z" 84 | 6,1,1606,"poor",17,283.7035,"westbrae",993.1582,"2021-01-14T16:00:00.000000Z" 85 | 3,2,665,"great",5,35.9905,"downtown",895.2665,"2021-01-14T20:00:00.000000Z" 86 | 2,1,1947,"good",18,482.0399,"alcatraz_ave",1291.3274,"2021-01-15T00:00:00.000000Z" 87 | 2,2,1574,"good",3,229.6737,"thowsand_oaks",1345.9786,"2021-01-15T04:00:00.000000Z" 88 | 3,3,926,"poor",16,204.6874,"thowsand_oaks",838.8013,"2021-01-15T08:00:00.000000Z" 89 | 2,2,1191,"good",9,966.9985,"thowsand_oaks",1150.4265,"2021-01-15T12:00:00.000000Z" 90 | 2,2,500,"great",2,932.7173,"berkeley_hills",1208.7444,"2021-01-15T16:00:00.000000Z" 91 | 5,3,1301,"poor",10,317.2890,"berkeley_hills",874.9099,"2021-01-15T20:00:00.000000Z" 92 | 3,3,1715,"good",19,793.4745,"downtown",784.2081,"2021-01-16T00:00:00.000000Z" 93 | 2,3,1939,"good",17,350.9787,"alcatraz_ave",724.2986,"2021-01-16T04:00:00.000000Z" 94 | 3,3,1003,"poor",2,557.6912,"south_side",726.9529,"2021-01-16T08:00:00.000000Z" 95 | 6,1,1653,"poor",6,720.0763,"downtown",568.7302,"2021-01-16T12:00:00.000000Z" 96 | 3,3,1107,"great",9,92.1411,"berkeley_hills",529.7522,"2021-01-16T16:00:00.000000Z" 97 | 4,2,296,"poor",9,493.5463,"alcatraz_ave",1027.4199,"2021-01-16T20:00:00.000000Z" 98 | 4,2,330,"great",9,712.7418,"westbrae",543.8303,"2021-01-17T00:00:00.000000Z" 99 | 4,3,1183,"good",1,672.5267,"berkeley_hills",601.2653,"2021-01-17T04:00:00.000000Z" 100 | 4,3,397,"poor",10,495.2094,"berkeley_hills",559.9281,"2021-01-17T08:00:00.000000Z" 101 | 4,2,1631,"good",13,107.9675,"alcatraz_ave",1268.5286,"2021-01-17T12:00:00.000000Z" 102 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Using QuestDB as a datasource for MindsDB 3 | 4 | ## Introduction 5 | 6 | [MindsDB](https://mindsdb.com/) enables you to use Machine Learning to ask predictive questions about your data 7 | and receive accurate answers from it, all **in SQL**. With MindsDB: 8 | 9 | - *Developers* can quickly add AI capabilities to their applications. 10 | - *Data scientists* can streamline MLOps by deploying ML models as 11 | [AI Tables](https://docs.mindsdb.com/sql/tutorials/ai-tables/?h=ai#deep-dive-into-the-ai-tables). 12 | - *Data analysts* can easily make forecasts on complex data, such as multivariate time-series with high 13 | cardinality, and visualize these in BI tools like [Grafana](https://grafana.com/), and 14 | [Tableau](https://www.tableau.com/). 15 | 16 | [QuestDB](https://questdb.io/) is **the fastest open-source**, column-oriented SQL database for time-series data. 17 | It has been designed and built for massively-parallelized vectorized execution and SIMD, as the de-facto backend 18 | for high-performance demanding applications in financial services, IoT, IIoT, ML, MLOps, DevOps and observability. 19 | QuestDB implements **ANSI SQL with additional extensions for time-specific queries**, which make it simple to correlate 20 | data from multiple sources using relational and time series [joins](https://questdb.io/docs/reference/sql/join), and 21 | execute [aggregation functions](https://questdb.io/docs/reference/function/aggregation) with simplicity and speed. 22 | In addition, QuestDB is resource efficient (comparatively cheaper than other projects to run in cloud environments), 23 | simple to install, manage, use, and stable in all [production environments](https://questdb.io/customers/). 24 | 25 | Combining both MindsDB and QuestDB gives you unbound prediction ability with SQL. You can perform all the pre-processing 26 | of your data inside QuestDB using its powerful and [unique extended SQL](https://questdb.io/docs/concept/sql-extensions), 27 | and then you can access these data from MindsDB, in its own [also unique SQL](https://docs.mindsdb.com/sql/), to produce 28 | powerful ML models. 29 | 30 | The main goal of this article is to gently introduce these two deep technologies and give you enough 31 | understanding to be able to undertake very ambitious ML projects. To that end we will: 32 | 33 | - Build a Docker image and spawn a container to run **MindsDB** and **QuestDB** together. 34 | - Add **QuestDB** as a datasource to **MindsDB** using a SQL Statement. 35 | - Create a table and add data for a simple ML use case using **QuestDB**'s web console. 36 | - Connect to **MindsDB** using its web console write some SQL. 37 | - Create a predictor for our ML use case. 38 | - Make some predictions about our data. 39 | 40 | Have fun! 41 | 42 | ## Requirements 43 | 44 | [docker](https://docs.docker.com/) is required to create an image and run our container. 45 | 46 | Software repositories in case you are inclined to look under the hood (**Give us a star!**): 47 | - MindsDB: [https://github.com/mindsdb/mindsdb](https://github.com/mindsdb/mindsdb). 48 | - QuestDB: [https://github.com/questdb/questdb](https://github.com/questdb/questdb). 49 | 50 | ## Running our Docker application 51 | 52 | Build the image first, with command: 53 | 54 | ```shell 55 | docker build -t questdb/mindsdb:latest . 56 | ``` 57 | 58 | which allows us to start our service container with command: 59 | 60 | ```shell 61 | docker run --rm \ 62 | -p 8812:8812 \ 63 | -p 9009:9009 \ 64 | -p 9000:9000 \ 65 | -p 8888:8888 \ 66 | -p 47334:47334 \ 67 | -p 47335:47335 \ 68 | -d \ 69 | --name qmdb \ 70 | questdb/mindsdb:latest 71 | ``` 72 | 73 | The container is run as user `quest`. It takes about 10 seconds to become responsive, logs can be followed in the terminal: 74 | 75 | ```shell 76 | docker logs -f qmdb 77 | ... 78 | http API: starting... 79 | mysql API: starting... 80 | mongodb API: starting... 81 | ... 82 | mongodb API: started on 47336 83 | mysql API: started on 47335 84 | http API: started on 47334 85 | ``` 86 | 87 | The container has these mount points: 88 | 89 | - **/home/quest**: User home dir. 90 | - **~/questdb/**: QuestDB's root directory. 91 | - **~/questdb/db/**: QuestDB's data root directory. 92 | - **~/backups/**: Directory for backups. 93 | - **~/csv/**: Directory for COPY operation. 94 | - **~/mindsdb/storage/**: MindsDB's data root directory. 95 | 96 | To manage it as root: 97 | 98 | ```shell 99 | docker run --rm -it --name qmdb-cli -u 0 questdb/mindsdb:latest bash 100 | ``` 101 | 102 | ## Adding data to QuestDB 103 | 104 | We can access QuestDB's web console at [localhost:9000](http://localhost:9000): 105 | 106 | ![QuestDB_web_console](images/questdb_web_console.png) 107 | 108 | and execute this DDL query to create a simple table (copy this query to the web console, select it and click `Run`): 109 | 110 | ```sql 111 | CREATE TABLE IF NOT EXISTS house_rentals_data ( 112 | number_of_rooms INT, 113 | number_of_bathrooms INT, 114 | sqft INT, 115 | location SYMBOL, 116 | days_on_market INT, 117 | initial_price FLOAT, 118 | neighborhood SYMBOL, 119 | rental_price FLOAT, 120 | ts TIMESTAMP 121 | ) TIMESTAMP(ts) PARTITION BY YEAR; 122 | ``` 123 | 124 | We can upload data from a [local CSV file](./sample_house_rentals_data.csv) to QuestDB: 125 | 126 | ```shell 127 | curl -F data=@sample_house_rentals_data.csv "http://localhost:9000/imp?forceHeader=true&name=house_rentals_data" 128 | ``` 129 | 130 | More information available [here!](https://questdb.io/docs/develop/insert-data#rest-api). 131 | 132 | We could equally populate table `house_rentals_data` with random data ([excellent tutorial on this](https://questdb.io/tutorial/2022/03/14/mock-sql-timeseries-data-questdb/)): 133 | 134 | ```sql 135 | INSERT INTO house_rentals_data SELECT * FROM ( 136 | SELECT 137 | rnd_int(1,6,0), 138 | rnd_int(1,3,0), 139 | rnd_int(180,2000,0), 140 | rnd_symbol('great', 'good', 'poor'), 141 | rnd_int(1,20,0), 142 | rnd_float(0) * 1000, 143 | rnd_symbol('alcatraz_ave', 'berkeley_hills', 'downtown', 'south_side', 'thowsand_oaks', 'westbrae'), 144 | rnd_float(0) * 1000 + 500, 145 | timestamp_sequence( 146 | to_timestamp('2021-01-01', 'yyyy-MM-dd'), 147 | 14400000000L 148 | ) 149 | FROM long_sequence(100) 150 | ); 151 | ``` 152 | 153 | Either way, this gives us 100 data points, one every 4 hours, from 2021-01-16T12:00:00.000000Z (QuestDB's timestamps 154 | are UTC with microsecond precision), conveniently downloaded to file [sample_house_rentals_data.csv](sample_house_rentals_data.csv). 155 | 156 | NOTE: If you tried the last query, you will have 200 rows, you can `truncate table house_rentals_data` and run the curl 157 | command again, in QuestDB data are immutable. 158 | 159 | ## Connecting to MindsDB 160 | 161 | We can access MindsDB's web console at [localhost:47334](http://localhost:47334): 162 | 163 | ![MindsDB_web_console](images/mindsdb_web_console.png) 164 | 165 | Only two databases are relevant to us, **questdb** and **mindsdb** 166 | 167 | ```sql 168 | SHOW DATABASES; 169 | +--------------------+ 170 | | Database | 171 | +--------------------+ 172 | | mindsdb | 173 | | files | 174 | | questdb | 175 | +--------------------+ 176 | 5 rows in set (0.34 sec) 177 | ``` 178 | 179 | To see `questdb` as a database we need to add it by executing: 180 | 181 | ```sql 182 | CREATE DATABASE questdb 183 | WITH ENGINE = "questdb", 184 | PARAMETERS = { 185 | "user": "admin", 186 | "password": "quest", 187 | "host": "0.0.0.0", 188 | "port": "8812", 189 | "database": "questdb" 190 | }; 191 | ``` 192 | 193 | ### questdb 194 | 195 | This is a read-only view on our QuestDB instance. We can query it leveraging the full power of 196 | QuestDB's unique SQL syntax because statements are sent from MindsDB to QuestDB without interpreting 197 | them. It only works for *SELECT* statements: 198 | 199 | ```sql 200 | SELECT * FROM questdb ( 201 | SELECT 202 | ts, 203 | neighborhood, 204 | sum(days_on_market) DaysLive, 205 | min(rental_price) MinRent, 206 | max(rental_price) MaxRent, 207 | avg(rental_price) AvgRent 208 | FROM house_rentals_data 209 | WHERE ts BETWEEN '2021-01-08' AND '2021-01-10' 210 | SAMPLE BY 1d FILL (0, 0, 0, 0) 211 | ); 212 | +--------------+----------------+----------+----------+----------+--------------------+ 213 | | ts | neighborhood | DaysLive | MinRent | MaxRent | AvgRent | 214 | +--------------+----------------+----------+----------+----------+--------------------+ 215 | | 1610064000.0 | south_side | 19 | 1285.338 | 1285.338 | 1285.338134765625 | 216 | | 1610064000.0 | downtown | 7 | 1047.14 | 1047.14 | 1047.1396484375 | 217 | | 1610064000.0 | berkeley_hills | 17 | 727.52 | 727.52 | 727.5198974609375 | 218 | | 1610064000.0 | westbrae | 36 | 1038.358 | 1047.342 | 1042.85009765625 | 219 | | 1610064000.0 | thowsand_oaks | 5 | 1067.319 | 1067.319 | 1067.318603515625 | 220 | | 1610064000.0 | alcatraz_ave | 0 | 0.0 | 0.0 | 0.0 | 221 | | 1610150400.0 | south_side | 10 | 694.403 | 694.403 | 694.4031982421875 | 222 | | 1610150400.0 | downtown | 16 | 546.798 | 643.204 | 595.0011291503906 | 223 | | 1610150400.0 | berkeley_hills | 4 | 1256.49 | 1256.49 | 1256.4903564453125 | 224 | | 1610150400.0 | westbrae | 0 | 0.0 | 0.0 | 0.0 | 225 | | 1610150400.0 | thowsand_oaks | 0 | 0.0 | 0.0 | 0.0 | 226 | | 1610150400.0 | alcatraz_ave | 14 | 653.924 | 1250.477 | 952.2005004882812 | 227 | | 1610236800.0 | south_side | 0 | 0.0 | 0.0 | 0.0 | 228 | | 1610236800.0 | downtown | 9 | 1357.916 | 1357.916 | 1357.9158935546875 | 229 | | 1610236800.0 | berkeley_hills | 0 | 0.0 | 0.0 | 0.0 | 230 | | 1610236800.0 | westbrae | 0 | 0.0 | 0.0 | 0.0 | 231 | | 1610236800.0 | thowsand_oaks | 0 | 0.0 | 0.0 | 0.0 | 232 | | 1610236800.0 | alcatraz_ave | 0 | 0.0 | 0.0 | 0.0 | 233 | +--------------+----------------+----------+----------+----------+--------------------+ 234 | ``` 235 | 236 | Beyond SELECT statements, for instance when we need to save the results of a query into a new table, 237 | we need to use QuestDB's web console available at [localhost:9000](http://localhost:9000): 238 | 239 | ```sql 240 | CREATE TABLE sample_query_results AS ( 241 | SELECT 242 | ts, 243 | neighborhood, 244 | sum(days_on_market) DaysLive, 245 | min(rental_price) MinRent, 246 | max(rental_price) MaxRent, 247 | avg(rental_price) AvgRent 248 | FROM house_rentals_data 249 | WHERE ts BETWEEN '2021-01-08' AND '2021-01-10' 250 | SAMPLE BY 1d FILL (0, 0, 0, 0) 251 | ) TIMESTAMP(ts) PARTITION BY MONTH; 252 | ``` 253 | 254 | ### mindsdb 255 | 256 | Contains the metadata tables necessary to create ML models: 257 | 258 | ```sql 259 | USE mindsdb; 260 | SHOW TABLES; 261 | +-------------------+ 262 | | Tables_in_mindsdb | 263 | +-------------------+ 264 | | models | 265 | | models_versions | 266 | +-------------------+ 267 | ``` 268 | 269 | ## Creating a predictor model 270 | 271 | We can create a predictor model `mindsdb.home_rentals_model_ts` to predict the `rental_price` 272 | for a `neighborhood` considering the past 20 days, and no additional features: 273 | 274 | ```sql 275 | CREATE MODEL mindsdb.home_rentals_model_ts FROM questdb ( 276 | SELECT 277 | neighborhood, 278 | rental_price, 279 | ts 280 | FROM house_rentals_data 281 | ) 282 | PREDICT rental_price ORDER BY ts GROUP BY neighborhood 283 | WINDOW 20 HORIZON 1; 284 | ``` 285 | 286 | This triggers MindsDB to create/train the model based on the full data available from QuestDB's table 287 | `house_rentals_data` (100 rows) as a timeseries on column `ts`. 288 | 289 | You can see the progress by monitoring the log output of the `mindsdb` Docker container. Creating/training a 290 | model will take time proportional to the number of features, i.e.cardinality of the source table as defined 291 | in the inner SELECT of the CREATE PREDICTOR statement, and the size of the corpus, i.e. number of rows. The 292 | model is a table in MindsDB: 293 | 294 | ```sql 295 | SHOW TABLES; 296 | +-----------------------+ 297 | | Tables_in_mindsdb | 298 | +-----------------------+ 299 | | information_schema | 300 | | models | 301 | | model_versions | 302 | | home_rentals_model_ts | 303 | +-----------------------+ 304 | ``` 305 | 306 | ## Describe the predictor model 307 | 308 | We can get more information about the trained model, how was the accuracy calculated or which columns are important for the model by executing the DESCRIBE statement. 309 | 310 | ```sql 311 | DESCRIBE MODEL mindsdb.home_rentals_model_ts; 312 | *************************** 1. row *************************** 313 | accuracies: {'complementary_smape_array_accuracy':0.859} 314 | outputs: ['rental_price'] 315 | inputs: ['neighborhood', 'ts', '__mdb_ts_previous_rental_price'] 316 | datasource: home_rentals_model_ts 317 | model: encoders --> dtype_dict --> dependency_dict --> model --> problem_definition --> identifiers --> imputers --> accuracy_functions 318 | ``` 319 | 320 | Or, to see how the model encoded the data prior to training we can execute: 321 | 322 | ```sql 323 | DESCRIBE MODEL mindsdb.home_rentals_model_ts.features; 324 | +--------------+-------------+------------------+---------+ 325 | | column | type | encoder | role | 326 | +--------------+-------------+------------------+---------+ 327 | | neighborhood | categorical | OneHotEncoder | feature | 328 | | rental_price | float | TsNumericEncoder | target | 329 | | ts | datetime | ArrayEncoder | feature | 330 | +--------------+-------------+------------------+---------+ 331 | ``` 332 | 333 | Additional information about the models and how they can be customized can be found on the [Lightwood docs](https://lightwood.io/). 334 | 335 | ## Querying MindsDB for predictions 336 | 337 | The latest `rental_price` value per `neighborhood` in table `questdb.house_rentals_data` 338 | (as per the [uploaded data](sample_house_rentals_data.csv)) can be obtained directly from QuestDB 339 | executing query: 340 | 341 | 342 | ```sql 343 | SELECT * FROM questdb ( 344 | SELECT 345 | neighborhood, 346 | rental_price, 347 | ts 348 | FROM house_rentals_data 349 | LATEST BY neighborhood 350 | ); 351 | +----------------+--------------+--------------+ 352 | | neighborhood | rental_price | ts | 353 | +----------------+--------------+--------------+ 354 | | thowsand_oaks | 1150.427 | 1610712000.0 | (2021-01-15 12:00:00.0) 355 | | south_side | 726.953 | 1610784000.0 | (2021-01-16 08:00:00.0) 356 | | downtown | 568.73 | 1610798400.0 | (2021-01-16 12:00:00.0) 357 | | westbrae | 543.83 | 1610841600.0 | (2021-01-17 00:00:00.0) 358 | | berkeley_hills | 559.928 | 1610870400.0 | (2021-01-17 08:00:00.0) 359 | | alcatraz_ave | 1268.529 | 1610884800.0 | (2021-01-17 12:00:00.0) 360 | +----------------+--------------+--------------+ 361 | ``` 362 | 363 | To predict the next value: 364 | 365 | ```sql 366 | SELECT 367 | tb.ts, 368 | tb.neighborhood, 369 | tb.rental_price as predicted_rental_price, 370 | tb.rental_price_explain as explanation 371 | FROM questdb.house_rentals_data AS ta 372 | JOIN mindsdb.home_rentals_model_ts AS tb 373 | WHERE ta.ts > LATEST; 374 | +---------------------+----------------+------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 375 | | ts | neighborhood | predicted_rental_price | explanation | 376 | +---------------------+----------------+------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 377 | | 2021-01-17 00:00:00 | downtown | 877.3007391233444 | {"predicted_value": 877.3007391233444, "confidence": 0.9991, "anomaly": null, "truth": null, "confidence_lower_bound": 379.43294697022424, "confidence_upper_bound": 1375.1685312764646} | 378 | | 2021-01-19 08:00:00 | westbrae | 923.1387395936794 | {"predicted_value": 923.1387395936794, "confidence": 0.9991, "anomaly": null, "truth": null, "confidence_lower_bound": 385.8327438509463, "confidence_upper_bound": 1460.4447353364124} | 379 | | 2021-01-15 16:00:00 | thowsand_oaks | 1418.678199780345 | {"predicted_value": 1418.678199780345, "confidence": 0.9991, "anomaly": null, "truth": null, "confidence_lower_bound": 1335.4600013965369, "confidence_upper_bound": 1501.8963981641532} | 380 | | 2021-01-17 12:00:00 | berkeley_hills | 646.5979284300436 | {"predicted_value": 646.5979284300436, "confidence": 0.9991, "anomaly": null, "truth": null, "confidence_lower_bound": 303.253838410034, "confidence_upper_bound": 989.9420184500532} | 381 | | 2021-01-18 12:00:00 | south_side | 1422.69481363723 | {"predicted_value": 1422.69481363723, "confidence": 0.9991, "anomaly": null, "truth": null, "confidence_lower_bound": 129.97617491441304, "confidence_upper_bound": 2715.413452360047} | 382 | | 2021-01-18 04:00:00 | alcatraz_ave | 1305.009073065412 | {"predicted_value": 1305.009073065412, "confidence": 0.9991, "anomaly": null, "truth": null, "confidence_lower_bound": 879.0232742685288, "confidence_upper_bound": 1730.994871862295} | 383 | +---------------------+----------------+------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 384 | ``` 385 | 386 | 387 | # Summary 388 | 389 | In this article, we have introduced **QuestDB** and **MindsDB** in a hands-on approach. QuestDB can help you store, 390 | analyse, and transform timeseries data, while MindsDB can help you make predictions about it. Albeit simple, our use case 391 | should have lowered the entry barrier to these two deep technologies, and now you can deepen your knowledge further by 392 | undertaking more ambitious ML projects. 393 | 394 | **Thank you for getting this far!!!**, if you liked this content we'd love to know your thoughts, please come and say 395 | hello in our welcoming communities: 396 | 397 | - [QuestDB Community Slack](https://slack.questdb.io/). 398 | - [MindsDB Community Slack](https://mindsdbcommunity.slack.com/join/shared_invite/zt-o8mrmx3l-5ai~5H66s6wlxFfBMVI6wQ#/shared-invite/email). 399 | 400 | Further reading: 401 | 402 | - [QuestDB documentation](https://questdb.io/docs/introduction/). 403 | - [MindsDB documentation](https://docs.mindsdb.com/). 404 | 405 | See you soon! 406 | --------------------------------------------------------------------------------