forked from oliver006/elasticsearch-test-data
-
Notifications
You must be signed in to change notification settings - Fork 0
/
es_test_data.py
executable file
·297 lines (234 loc) · 11.9 KB
/
es_test_data.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
#!/usr/bin/python
import nest_asyncio
nest_asyncio.apply()
import json
import time
import logging
import random
import string
import uuid
from datetime import datetime
from datetime import timedelta
import tornado.gen
import tornado.httpclient
import tornado.ioloop
import tornado.options
try:
xrange
range = xrange
except NameError:
pass
async_http_client = tornado.httpclient.AsyncHTTPClient()
headers = tornado.httputil.HTTPHeaders({"content-type": "application/json"})
id_counter = 0
upload_data_count = 0
_dict_data = None
def delete_index(idx_name):
try:
url = "%s/%s?refresh=true" % (tornado.options.options.es_url, idx_name)
request = tornado.httpclient.HTTPRequest(url, headers=headers, method="DELETE", request_timeout=240, auth_username=tornado.options.options.username, auth_password=tornado.options.options.password, validate_cert=tornado.options.options.validate_cert)
response = tornado.httpclient.HTTPClient().fetch(request)
logging.info('Deleting index "%s" done %s' % (idx_name, response.body))
except tornado.httpclient.HTTPError:
pass
def create_index(idx_name):
schema = {
"settings": {
"number_of_shards": tornado.options.options.num_of_shards,
"number_of_replicas": tornado.options.options.num_of_replicas
},
"refresh": True
}
body = json.dumps(schema)
url = "%s/%s" % (tornado.options.options.es_url, idx_name)
try:
logging.info('Trying to create index %s' % (url))
request = tornado.httpclient.HTTPRequest(url, headers=headers, method="PUT", body=body, request_timeout=240, auth_username=tornado.options.options.username, auth_password=tornado.options.options.password, validate_cert=tornado.options.options.validate_cert)
response = tornado.httpclient.HTTPClient().fetch(request)
logging.info('Creating index "%s" done %s' % (idx_name, response.body))
except tornado.httpclient.HTTPError:
logging.info('Looks like the index exists already')
pass
@tornado.gen.coroutine
def upload_batch(upload_data_txt):
try:
request = tornado.httpclient.HTTPRequest(tornado.options.options.es_url + "/_bulk",
method="POST",
body=upload_data_txt,
headers=headers,
request_timeout=tornado.options.options.http_upload_timeout,
auth_username=tornado.options.options.username, auth_password=tornado.options.options.password, validate_cert=tornado.options.options.validate_cert)
response = yield async_http_client.fetch(request)
except Exception as ex:
logging.error("upload failed, error: %s" % ex)
return
result = json.loads(response.body.decode('utf-8'))
res_txt = "OK" if not result['errors'] else "FAILED"
took = int(result['took'])
logging.info("Upload: %s - upload took: %5dms, total docs uploaded: %7d" % (res_txt, took, upload_data_count))
def get_data_for_format(format):
split_f = format.split(":")
if not split_f:
return None, None
field_name = split_f[0]
field_type = split_f[1]
return_val = ''
if field_type == "bool":
return_val = random.choice([True, False])
elif field_type == "str":
min = 3 if len(split_f) < 3 else int(split_f[2])
max = min + 7 if len(split_f) < 4 else int(split_f[3])
length = generate_count(min, max)
return_val = "".join([random.choice(string.ascii_letters + string.digits) for x in range(length)])
elif field_type == "int":
min = 0 if len(split_f) < 3 else int(split_f[2])
max = min + 100000 if len(split_f) < 4 else int(split_f[3])
return_val = generate_count(min, max)
elif field_type == "ipv4":
return_val = "{0}.{1}.{2}.{3}".format(generate_count(0, 245),generate_count(0, 245),generate_count(0, 245),generate_count(0, 245))
elif field_type in ["ts", "tstxt"]:
now = int(time.time())
per_day = 24 * 60 * 60
min = now - 30 * per_day if len(split_f) < 3 else int(split_f[2])
max = now + 30 * per_day if len(split_f) < 4 else int(split_f[3])
ts = generate_count(min, max)
return_val = int(ts * 1000) if field_type == "ts" else datetime.fromtimestamp(ts).strftime("%Y-%m-%dT%H:%M:%S.000-0000")
elif field_type == "words":
min = 2 if len(split_f) < 3 else int(split_f[2])
max = min + 8 if len(split_f) < 4 else int(split_f[3])
count = generate_count(min, max)
words = []
for _ in range(count):
word_len = random.randrange(3, 10)
words.append("".join([random.choice(string.ascii_letters + string.digits) for x in range(word_len)]))
return_val = " ".join(words)
elif field_type == "dict":
global _dict_data
min = 2 if len(split_f) < 3 else int(split_f[2])
max = min + 8 if len(split_f) < 4 else int(split_f[3])
count = generate_count(min, max)
return_val = " ".join([random.choice(_dict_data).strip() for _ in range(count)])
elif field_type == "text":
text = ["text1", "text2", "text3"] if len(split_f) < 3 else split_f[2].split("-")
min = 1 if len(split_f) < 4 else int(split_f[3])
max = min + 1 if len(split_f) < 5 else int(split_f[4])
count = generate_count(min, max)
words = []
for _ in range(count):
words.append(""+random.choice(text))
return_val = " ".join(words)
return field_name, return_val
def generate_count(min, max):
if min == max:
return max
elif min > max:
return random.randrange(max, min);
else:
return random.randrange(min, max);
def generate_random_doc(format):
global id_counter
res = {}
for f in format:
f_key, f_val = get_data_for_format(f)
if f_key:
res[f_key] = f_val
if not tornado.options.options.id_type:
return res
if tornado.options.options.id_type == 'int':
res['_id'] = id_counter
id_counter += 1
elif tornado.options.options.id_type == 'uuid4':
res['_id'] = str(uuid.uuid4())
return res
def set_index_refresh(val, index_name):
params = {"index": {"refresh_interval": val}}
body = json.dumps(params)
url = "%s/%s/_settings" % (tornado.options.options.es_url, index_name)
try:
request = tornado.httpclient.HTTPRequest(url, headers=headers, method="PUT", body=body, request_timeout=240, auth_username=tornado.options.options.username, auth_password=tornado.options.options.password, validate_cert=tornado.options.options.validate_cert)
http_client = tornado.httpclient.HTTPClient()
http_client.fetch(request)
logging.info('Set index refresh to %s' % val)
except Exception as ex:
logging.exception(ex)
@tornado.gen.coroutine
def generate_test_data(index_name):
global upload_data_count
if tornado.options.options.force_init_index:
delete_index(index_name)
create_index(index_name)
# todo: query what refresh is set to, then restore later
if tornado.options.options.set_refresh:
set_index_refresh("-1")
if tornado.options.options.out_file:
out_file = open(tornado.options.options.out_file, "w")
else:
out_file = None
if tornado.options.options.dict_file:
global _dict_data
with open(tornado.options.options.dict_file, 'r') as f:
_dict_data = f.readlines()
logging.info("Loaded %d words from the %s" % (len(_dict_data), tornado.options.options.dict_file))
format = tornado.options.options.format.split(',')
if not format:
logging.error('invalid format')
exit(1)
ts_start = int(time.time())
upload_data_txt = ""
logging.info("Generating %d docs, upload batch size is %d" % (tornado.options.options.count,
tornado.options.options.batch_size))
for num in range(0, tornado.options.options.count):
item = generate_random_doc(format)
if out_file:
out_file.write("%s\n" % json.dumps(item))
cmd = {'index': {'_index': index_name,
'_type': tornado.options.options.index_type}}
if '_id' in item:
cmd['index']['_id'] = item['_id']
upload_data_txt += json.dumps(cmd) + "\n"
upload_data_txt += json.dumps(item) + "\n"
upload_data_count += 1
if upload_data_count % tornado.options.options.batch_size == 0:
yield upload_batch(upload_data_txt)
upload_data_txt = ""
# upload remaining items in `upload_data_txt`
if upload_data_txt:
yield upload_batch(upload_data_txt)
if tornado.options.options.set_refresh:
set_index_refresh("1s")
if out_file:
out_file.close()
took_secs = int(time.time() - ts_start)
logging.info("Done - total docs uploaded: %d, took %d seconds" % (tornado.options.options.count, took_secs))
if __name__ == '__main__':
tornado.options.define("es_url", type=str, default='http://localhost:9200/', help="URL of your Elasticsearch node")
tornado.options.define("index_name", type=str, default='test_data', help="Name of the index to store your messages")
tornado.options.define("index_type", type=str, default='test_type', help="Type")
tornado.options.define("batch_size", type=int, default=1000, help="Elasticsearch bulk index batch size")
tornado.options.define("num_of_shards", type=int, default=2, help="Number of shards for ES index")
tornado.options.define("http_upload_timeout", type=int, default=3, help="Timeout in seconds when uploading data")
tornado.options.define("count", type=int, default=100000, help="Number of docs to generate")
tornado.options.define("format", type=str, default='name:str,age:int,last_updated:ts', help="message format")
tornado.options.define("num_of_replicas", type=int, default=0, help="Number of replicas for ES index")
tornado.options.define("force_init_index", type=bool, default=False, help="Force deleting and re-initializing the Elasticsearch index")
tornado.options.define("set_refresh", type=bool, default=False, help="Set refresh rate to -1 before starting the upload")
tornado.options.define("out_file", type=str, default=False, help="If set, write test data to out_file as well.")
tornado.options.define("id_type", type=str, default=None, help="Type of 'id' to use for the docs, valid settings are int and uuid4, None is default")
tornado.options.define("dict_file", type=str, default=None, help="Name of dictionary file to use")
tornado.options.define("username", type=str, default=None, help="Username for elasticsearch")
tornado.options.define("password", type=str, default=None, help="Password for elasticsearch")
tornado.options.define("validate_cert", type=bool, default=True, help="SSL validate_cert for requests. Use false for self-signed certificates.")
tornado.options.define("time_series", type=str, default=None, help="""Create time series index.
Require a string seperated by comma like: '%Y.%m.%d,2021.01.01,5',
the first part is time format, the second part is start date, the third
part define days from start date.""")
tornado.options.parse_command_line()
if tornado.options.options.time_series:
format, str_date, span = tornado.options.options.time_series.replace(' ', '').split(',')
start_date = datetime.strptime(str_date, format)
for i in range(int(span)):
date = (start_date + timedelta(days=i)).strftime(format)
index_name = tornado.options.options.index_name + '-' + date
tornado.ioloop.IOLoop.instance().run_sync(index_name)
else:
tornado.ioloop.IOLoop.instance().run_sync(tornado.options.options.index_name)