aggregate multiple recursive logstash - elasticsearch

I am using logstash with input jdbc, and would like to embed one object inside another with aggregate.
How can I use add recursive?
Ie add an object inside another object?
This would be an example:
{
"_index": "my-index",
"_type": "test",
"_id": "1",
"_version": 1,
"_score": 1,
"_source": {
"id": "1",
"properties": {
"nested_1": [
{
"A": 0,
"B": "true",
"C": "PEREZ, MATIAS ROGELIO Y/O",
"Nested_2": [
{
"Z1": "true",
"Z2": "99999"
}
},
{
"A": 0,
"B": "true",
"C": "SALVADOR MATIAS ROMERO",
"Nested_2": [
{
"Z1": "true",
"Z2": "99999"
}
}
]
}
}
}
I'm using something like that but it doesn't work
aggregate {
task_id => "%{id}"
code => "
map['id'] = event.get('id')
map['nested_1_list'] ||= []
map['nested_1'] ||= []
if (event.get('id') != nil)
if !( map['nested_1_list'].include?event.get('id') )
map['nested_1_list'] << event.get('id')
map['nested_1'] << {
'A' => event.get('a'),
'B' => event.get('b'),
'C' => event.get('c'),
map['nested_2_list'] ||= []
map['nested_2'] ||= []
if (event.get('id_2') != nil)
if !( map['nested_2_list'].include?event.get('id_2') )
map['nested_2_list'] << event.get('id_2')
map['nested_2'] << {
'Z1' => event.get('z1'),
'Z2' => event.get('z2')
}
end
end
}
end
end
event.cancel()
"
push_previous_map_as_event => true
timeout => 3
}
Any idea how to implement this?........................
..........

Finally what I did was, generate the JSON from the input, that is, from a stored procedure that is consumed from a view (vw) from the input statement of logstash.
Once consumed, I process it as json and I already have that json to work as one more variable.
# Convierto el string a json real (quita comillas y barras invertidas)
ruby {
code => "
require 'json'
json_value = JSON.parse(event.get('field_db').to_s)
event.set('field_convert_to_json',json_value)
"
}

Maybe you can try this. Note This will be applicable only when you want to have a single object and not an array of object.
Please do visit my blog for other formats.
https://xyzcoder.github.io/2020/07/29/indexing-documents-using-logstash-and-python.html
input {
jdbc {
jdbc_driver_library => "/usr/share/logstash/javalib/mssql-jdbc-8.2.2.jre11.jar"
jdbc_driver_class => "com.microsoft.sqlserver.jdbc.SQLServerDriver"
jdbc_connection_string => "jdbc:sqlserver://host.docker.internal;database=StackOverflow2010;user=pavan;password=pavankumar#123"
jdbc_user => "pavan"
jdbc_password => "pavankumar#123"
statement => "select top 500 p.Id as PostId,p.AcceptedAnswerId,p.AnswerCount,p.Body,u.Id as userid,u.DisplayName,u.Location
from StackOverflow2010.dbo.Posts p inner join StackOverflow2010.dbo.Users u
on p.OwnerUserId=u.Id"
}
}
filter {
aggregate {
task_id => "%{postid}"
code => "
map['postid'] = event.get('postid')
map['accepted_answer_id'] = event.get('acceptedanswerid')
map['answer_count'] = event.get('answercount')
map['body'] = event.get('body')
map['user'] = {
'id' => event.get('userid'),
'displayname' => event.get('displayname'),
'location' => event.get('location')
}
map['user']['test'] = {
'test_body' => event.get('postid')
}
event.cancel()"
push_previous_map_as_event => true
timeout => 30
}
}
output {
elasticsearch {
hosts => ["http://elasticsearch:9200", "http://elasticsearch:9200"]
index => "stackoverflow_top"
}
stdout {
codec => rubydebug
}
}
and my output is
{
"_index" : "stackoverflow_top",
"_type" : "_doc",
"_id" : "S8WEmnMBrXsRTNbKO0JJ",
"_score" : 1.0,
"_source" : {
"#version" : "1",
"body" : """<p>How do I store binary data in MySQL?</p>
""",
"#timestamp" : "2020-07-29T12:20:22.649Z",
"answer_count" : 10,
"user" : {
"displayname" : "Geoff Dalgas",
"location" : "Corvallis, OR",
"test" : {
"test_body" : 17
},
"id" : 2
},
"postid" : 17,
"accepted_answer_id" : 26
}
Here test object is nested into the user object

Related

How to fetch field from array of objects in Elasticsearch Index as CSV file to Google Cloud Storage Using Logstash

I am using ElasticSearch to index data and wanted to export few fields from index created every day to Google cloud storage, How to get fields from array of objects in elastic search index and send them as csv file to GCS bucket using Logstash
Tried below conf to fetch nested fields from index:
input {
elasticsearch {
hosts => "host:443"
user => "user"
ssl => true
connect_timeout_seconds => 600
request_timeout_seconds => 600
password => "pwd"
ca_file => "ca.crt"
index => "test"
query => '
{
"_source": ["obj1.Name","obj1.addr","obj1.obj2.location", "Hierarchy.categoryUrl"],
"query": {
"match_all": {}
}
}
'
}
}
filter {
mutate {
rename => {
"[obj1][Name]" => "col1"
"[obj1][addr]" => "col2"
"[obj1][obj2][location]" => "col3"
"[Hierarchy][0][categoryUrl]" => "col4"
}
}
}
output {
google_cloud_storage {
codec => csv {
include_headers => true
columns => [ "col1", "col2","col3"]
}
bucket => "bucket"
json_key_file => "creds.json"
temp_directory => "/tmp"
log_file_prefix => "log_gcs"
max_file_size_kbytes => 1024
date_pattern => "%Y-%m-%dT%H:00"
flush_interval_secs => 600
gzip => false
uploader_interval_secs => 600
include_uuid => true
include_hostname => true
}
}
How to get field populated to above csv from array of objects, in below example wanted to fetch categoryUrl from the first object of an array and populate to csv table and send it to GCS Bucket:
have tried below approaches :
"_source": ["obj1.Name","obj1.addr","obj1.obj2.location", "Hierarchy.categoryUrl"]
and
"_source": ["obj1.Name","obj1.addr","obj1.obj2.location", "Hierarchy[0].categoryUrl"]
with
mutate {
rename => {
"[obj1][Name]" => "col1"
"[obj1][addr]" => "col2"
"[obj1][obj2][location]" => "col3"
"[Hierarchy][0][categoryUrl]" => "col4"
}
for input sample :
"Hierarchy" : [
{
"level" : "1",
"category" : "test",
"categoryUrl" : "testurl1"
},
{
"level" : "2",
"category" : "test2",
"categoryUrl" : "testurl2"
}}
Attaching sample document where I am trying to fetch merchandisingHierarchy[0].categoryUrl and pricingInfo[0].basePrice :
{
"_index" : "amulya-test",
"_type" : "_doc",
"_id" : "ldZPJoYBFi8LOEDK_M2f",
"_score" : 1.0,
"_ignored" : [
"itemDetails.description.keyword"
],
"_source" : {
"itemDetails" : {
"compSku" : "202726",
"compName" : "abc.com",
"compWebsite" : "abc.com",
"title" : "Monteray 38.25 in. x 73.375 in. Frameless Hinged Corner Shower Enclosure in Brushed Nickel",
"description" : "Create the modthroom of your dreams with the clean lines of the VIGO Monteray Frameless Shower Enclosure. Solid 3/8 in. tempered glass combined with stainless steel and solid brass construction makes this enclosure strong and long-lasting. The sleek, reversible, outward-opening door features a convenient towel bar. This versatile enclosure can be installed on a tile floor or with a VIGO Shower Base. With a single water deflector along the bottom seal strip, water is redirected back into the shower to keep your bathroom dry, clean, and pristine.",
"modelNumber" : "VG6011BNCL40",
"upc" : "8137756684",
"hasVariations" : false,
"productDetailsBulletPoints" : [ ],
"itemUrls" : {
"productPageUrl" : "https://.abc.com/p/VIGO-Monteray-38-in-x-73-375-in-Frameless-Hinged-Corner-Shower-Enclosure-in-Brushed-Nickel-VG6011BNCL40/202722616",
"primaryImageUrl" : "https://images.thdstatic.com/productImages/d77d9e8b-1ea1-4811-a470-8364c8e47402/svn/vigo-shower-enclosures-vg6011bncl40-64_600.jpg",
"secondaryImageUrls" : [
"https://images.thdstatic.com/productImages/d77d9e8b-1e1-4811-a470-8364c8e47402/svn/vigo-shower-enclosures-vg6011bncl40-64_1000.jpg",
"https://images.thdstatic.com/productImages/db539ff9-6df-48c2-897a-18dd1e1794e3/svn/vigo-shower-enclosures-vg6011bncl40-e1_1000.jpg",
"https://images.thdstatic.com/productImages/47c5090b-49a-46bc-a36d-921ddae5e1ab/svn/vigo-shower-enclosures-vg6011bncl40-40_1000.jpg",
"https://images.thdstatic.com/productImages/add6691c-a02-466d-9a1a-47200b05685e/svn/vigo-shower-enclosures-vg6011bncl40-a0_1000.jpg",
"https://images.thdstatic.com/productImages/d638230e-0d9-40c9-be93-7f7bf24f0732/svn/vigo-shower-enclosures-vg6011bncl40-1d_1000.jpg"
]
}
},
"merchandisingHierarchy" : [
{
"level" : "1",
"category" : "Home",
"categoryUrl" : "host/"
},
{
"level" : "2",
"category" : "Bath",
"categoryUrl" : "host/b/Bath/N-5yc1vZbzb3"
},
{
"level" : "3",
"category" : "Showers",
"categoryUrl" : "host/b/Bath-Showers/N-5yc1vZbzcd"
},
{
"level" : "4",
"category" : "Shower Doors",
"categoryUrl" : "host/b/Bath-Showers-Shower-Doors/N-5yc1vZbzcg"
},
{
"level" : "5",
"category" : "Shower Enclosures",
"categoryUrl" : "host/b/Bath-Showers-Shower-Doors-Shower-Enclosures/N-5yc1vZcbn2"
}
],
"reviewsAndRatings" : {
"pdtReviewCount" : 105
},
"additionalAttributes" : {
"isAddon" : false
},
"productSpecifications" : {
"Warranties" : { },
"Details" : { },
"Dimensions" : { }
},
"promoDetails" : [
{
"promoName" : "Save $150.00 (15%)",
"promoPrice" : 849.9
}
],
"locationDetails" : { },
"storePickupDetails" : {
"deliveryText" : "Get it by Mon, Feb 20",
"toEddDate" : "Mon, Feb 20",
"isBackordered" : false,
"selectedEddZipcode" : "20147",
"shipToStoreEnabled" : true,
"homeDeliveryEnabled" : true,
"scheduledDeliveryEnabled" : false
},
"recommendedProducts" : [ ],
"pricingInfo" : [
{
"type" : "SAS",
"offerPrice" : 849.9,
"sellerName" : "abc.com",
"onClearance" : false,
"inStock" : true,
"isBuyBoxWinner" : true,
"promo" : [
{
"onPromo" : true,
"promoName" : "Save $150.00 (15%)",
"promoPrice" : 849.9
}
],
"basePrice" : 999.9,
"priceVariants" : [
{
"basePrice" : 999.9,
"offerPrice" : 849.9
}
],
"inventoryDetails" : {
"stockInStore" : false,
"stockOnline" : true
}
}
]
}
}
You can do it like this:
input {
elasticsearch {
...
query => '
{
"_source": ["merchandisingHierarchy.categoryUrl"],
"query": {
"match_all": {}
}
}
'
}
}
filter {
mutate {
add_field => {
"col1" => "%{[merchandisingHierarchy][0][categoryUrl]}"
"col2" => "%{[pricingInfo][0][basePrice]}"
}
}
}
output {
stdout {
codec => csv {
include_headers => true
columns => [ "col1"]
}
}
}
I've tested with your sample document and I get the output below, which looks like is working per your expectation:
col1,col2
host/,999.9

Filter by Id in nested Elasticsearch objects

I am trying to achieve not common thing and I am struggling with it hard.
I have such document:
{
"_index": "users",
"_type": "_doc",
"_id": "07e4588c-6102-4be2-9518-cabaa40726e0",
"_score": 1,
"_source": {
"UserId": "07e4588c-6102-4be2-9518-cabaa40726e0",
...
"UserField": [
{
"Id": "3fa8f6aa-e4d7-4762-9287-d53de515954a",
"Value": "",
"UserId": "07e4588c-6102-4be2-9518-cabaa40726e0",
"FieldId": "3acca766-9f4a-4d7e-9ffb-262b7a26c971",
"TenantKey": "b1ef9a58-bcbf-4069-ae4a-3efea1a51bba"
},
{
"Id": "7b9219c7-4157-465c-9904-4e529cbf2f66",
"Value": "Mason",
"UserId": "07e4588c-6102-4be2-9518-cabaa40726e0",
"FieldId": "f5f67cb3-c7e6-42a9-a299-06511240bda0",
"TenantKey": "b1ef9a58-bcbf-4069-ae4a-3efea1a51bba"
},
{
"Id": "b65ba0e9-64b7-4203-8ac1-0984dad642a5",
"Value": "Alex",
"UserId": "07e4588c-6102-4be2-9518-cabaa40726e0",
"FieldId": "43bf99f4-20cf-48c3-9d09-d4488e9f0933",
"TenantKey": "b1ef9a58-bcbf-4069-ae4a-3efea1a51bba"
},
}
],
...
}
}
}
}
As you can see here, I have an array of UserFields and this is nested object in Elasticsearch. My goal is to search by Values of that fields, but I need particular FieldId and which always the same, described in static class.
So In my .NET code I can write ..x.FieldId == FieldIds.Firstname. Is it possible somehow to get an advantage of search, firstly filtering needed fields and then search by their Value property.
What I've already tried?
var filters = new List<Func<QueryContainerDescriptor<UserSearchItem>, QueryContainer>>();
filters.Add(fq => fq.Terms(t => t.Field(Infer.Field<UserSearchItem>(x => x.UserField.First(x => x.FieldId == FieldIds.Firstname)))));
var searchResponse =
_client.Search<UserSearchItem>(x => x.Query(q => q
.Nested(t => t
.Path(Infer.Field<UserSearchItem>(x => x.UserField))
.Query(q => q.Bool(f => f.Filter(filters))))));
No luck
And this one, even QueryContainer not applied by operator &
container &= new NestedQuery
{
Path = Infer.Field<UserSearchItem>(x => x.UserField),
Query = new BoolQuery()
{
Should = new List<QueryContainer>()
{
new MatchQuery()
{
Field =
Infer.Field<UserSearchItem>(x => x.UserField.First(x => x.FieldId == FieldIds.Firstname)).Name,
Query = $"{req.Name}"
},
new MatchQuery()
{
Field =
Infer.Field<UserSearchItem>(x => x.UserField.First(x => x.FieldId == FieldIds.Lastname)).Name,
Query = $"{req.Name}"
},
new MatchQuery()
{
Field =
Infer.Field<UserSearchItem>(x => x.UserField.First(x => x.FieldId == FieldIds.Middlename)).Name,
Query = $"{req.Name}"
}
}
}};
Thanks for any help in advance!
Here is the query in plain json
{
"query" : {
"nested" : {
"path" : "UserField",
"query" : {
"bool" : {
"must" : [
{
"term" : {"UserField.FieldId" : Your_STATIC_FIELD}
},
{
"term" : {"UserField.Value" : "whatever_value_you_Want"}
}
]
}
}
}
}
}
First try out this query in kibana > devTools. If you get the desired result, translate it into a query in .NET . You don't need anything very complicated to get this to work. Its just a nested bool query.
HTH.

Proper way to Parse a Payload in Ruby

I have the following payload:
[{:payload=>
"{\"user\":\"test\",\"job\":\"Test\",\"username\":\"Bob\",\"blocks\":[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"this is the title\"}},{\"type\":\"context\",\"elements\":[{\"type\":\"mrkdwn\",\"text\":\"Test\"}]},{\"type\":\"divider\"}]}"}]
I'm trying to figure out how to extract it. I tried
JSON.parse(response)
But I get the following error
TypeError: no implicit conversion of Hash into String
How can I extract this value to something where I can do something like:
response.job == "test" ?
Let's assume that you meant to say:
response = [{:payload => "{\"user\":\"test\",\"job\":\"Test\",\"username\":\"Bob\",\"blocks\":[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"this is the title\"}},{\"type\":\"context\",\"elements\":[{\"type\":\"mrkdwn\",\"text\":\"Test\"}]},{\"type\":\"divider\"}]}"}]
Then response is an array with one element. That one element is a hash. You would thus access the payload with:
payload = JSON.parse(response.first[:payload])
=> {
"user" => "test",
"job" => "Test",
"username" => "Bob",
"blocks" => [
[0] {
"type" => "section",
"text" => {
"type" => "mrkdwn",
"text" => "this is the title"
}
},
[1] {
"type" => "context",
"elements" => [
[0] {
"type" => "mrkdwn",
"text" => "Test"
}
]
},
[2] {
"type" => "divider"
}
]
}
The payload object is then a hash and its child elements can be accessed using the standard [] call:
job = payload['job']
=> "Test"

Logstash 2.3.4 How to load nested document in elasticsearch using logstash-jdbc plugin

I am currently using elasticsearch 2.3.4 and logstash 2.3.4 to load relational data from Oracle db into my elasticsearch index using logstash-jdbc plugin. As suggested in various posts, I am using aggregate filter for this. Still I am not able to load the inner nested object in the document. The values are not getting mapped to fields and are displayed as NULL.
I have two related entities with following data:
CREATE TABLE DEPARTMENT (
id NUMBER PRIMARY KEY,
name VARCHAR2(4000) NOT NULL
)
CREATE TABLE EMPLOYEE (
id NUMBER PRIMARY KEY,
name VARCHAR2(4000) NOT NULL,
departmentid NUMBER,
CONSTRAINT EMPLOYEE_FK FOREIGN KEY (departmentid) REFERENCES DEPARTMENT(id)
)
insert into DEPARTMENT values (1, 'dept1');
insert into DEPARTMENT values (2, 'dept2');
insert into DEPARTMENT values (3, 'dept3');
insert into DEPARTMENT values (4, 'dept4');
insert into EMPLOYEE values (1, 'emp1', 1);
insert into EMPLOYEE values (2, 'emp2', 1);
insert into EMPLOYEE values (3, 'emp3', 1);
insert into EMPLOYEE values (4, 'emp4', 2);
insert into EMPLOYEE values (5, 'emp5', 2);
insert into EMPLOYEE values (6, 'emp6', 3);`
Here is my mapping:
{
"mappings": {
"departments": {
"properties": {
"id": {
"type": "integer"
},
"deptName": {
"type": "string"
},
"employee_details": {
"type": "nested",
"properties": {
"empId": {
"type": "integer"
},
"empName": {
"type": "string"
}
}
}
}
}
}
}
And this is my logstash configuration:
input{
jdbc{
jdbc_validate_connection => true
jdbc_connection_string => "jdbc:oracle:thin:#host:port:db"
jdbc_user => "user"
jdbc_password => "pwd"
jdbc_driver_library => "../vendor/jar/ojdbc14.jar"
jdbc_driver_class => "Java::oracle.jdbc.driver.OracleDriver"
statement => "SELECT
department.id AS id,
department.name AS deptName,
employee.id AS empId,
employee.name AS empName
FROM department LEFT JOIN employee
ON department.id = employee.departmentid
ORDER BY id"
}
}
filter{
aggregate {
task_id => "%{id}"
code => "
map['id'] = event['id']
map['deptName'] = event['deptName'] #solution - deptName should be in smaller case and other fields too.
map['employee_details'] ||= []
map['employee_details'] << {'empId' => event['empId], 'empName' => event['empName'] }
"
push_previous_map_as_event => true
timeout => 5
timeout_tags => ['aggregated']
}
}
output{
stdout{ codec => rubydebug }
elasticsearch{
action => "index"
index => "my_index"
document_type => "departments"
document_id => "%{id}"
hosts => "localhost:9200"
}
}
When i perform a XGET on all documents:
curl -XGET 'localhost:9200/my_index/_search/?pretty=true&q=:
The values are not mapped to fields and displayed as NULL:
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 4,
"max_score": 1,
"hits": [
{
"_index": "my_index",
"_type": "departments",
"_id": "2",
"_score": 1,
"_source": {
"id": 2,
"deptName": null,
"employee_details": [
{
"empId": null,
"empName": null
},
{
"empId": null,
"empName": null
}
],
"#version": "1",
"#timestamp": "2019-05-14T10:47:33.477Z",
"tags": [
"aggregated"
]
}
},
{
"_index": "my_index",
"_type": "departments",
"_id": "4",
"_score": 1,
"_source": {
"id": 4,
"deptname": "dept4",
"empid": null,
"empname": null,
"#version": "1",
"#timestamp": "2019-05-14T10:47:33.367Z",
"deptName": null,
"employee_details": [
{
"empId": null,
"empName": null
}
]
}
},
{
"_index": "my_index",
"_type": "departments",
"_id": "1",
"_score": 1,
"_source": {
"id": 1,
"deptName": null,
"employee_details": [
{
"empId": null,
"empName": null
},
{
"empId": null,
"empName": null
},
{
"empId": null,
"empName": null
}
],
"#version": "1",
"#timestamp": "2019-05-14T10:47:33.477Z",
"tags": [
"aggregated"
]
}
},
{
"_index": "my_index",
"_type": "departments",
"_id": "3",
"_score": 1,
"_source": {
"id": 3,
"deptName": null,
"employee_details": [
{
"empId": null,
"empName": null
}
],
"#version": "1",
"#timestamp": "2019-05-14T10:47:33.492Z",
"tags": [
"aggregated"
]
}
}
]
}
}
rubydebug suggests the values are set to 'nil'. Could anyone please help me with what I am doing wrong here?
Here is a snippet from stdout for document with id = 1:
{
"id" => 1.0,
"deptname" => "dept1",
"empid" => 1.0,
"empname" => "emp1",
"#version" => "1",
"#timestamp" => "2019-05-14T12:32:14.272Z"
}
{
"id" => 1.0,
"deptname" => "dept1",
"empid" => 2.0,
"empname" => "emp2",
"#version" => "1",
"#timestamp" => "2019-05-14T12:32:15.272Z"
}
{
"id" => 1.0,
"deptname" => "dept1",
"empid" => 3.0,
"empname" => "emp3",
"#version" => "1",
"#timestamp" => "2019-05-14T12:32:15.272Z"
}
{
"id" => 1.0,
"deptName" => nil,
"employee_details" => [
[0] {
"empId" => nil,
"empName" => nil
},
[1] {
"empId" => nil,
"empName" => nil
},
[2] {
"empId" => nil,
"empName" => nil
}
],
"#version" => "1",
"#timestamp" => "2019-05-14T12:32:15.381Z",
"tags" => [
[0] "aggregated"
]
}
Following code works for me .
input {
jdbc{
jdbc_validate_connection => true
jdbc_connection_string => "----/employees"
jdbc_user => "---"
jdbc_password => "--"
jdbc_driver_library => "/home/ilsa/mysql-connector-java-5.1.36-bin.jar"
jdbc_driver_class => "com.mysql.jdbc.Driver"
statement => "SELECT
e.emp_no as employee_number,
birth_date, first_name, last_name, gender, hire_date, t.title AS titlename,
t.from_date AS titlefrom_date, t.to_date AS titleto_date, d.dept_no AS departmentnumber,
ds.dept_name AS departmentname, d.from_date AS departmentfrom_date, d.to_date AS departmentto_date
FROM employees e
LEFT JOIN(titles t, dept_emp d, departments ds)
ON(e.emp_no = t.emp_no AND e.emp_no = d.emp_no AND d.dept_no = ds.dept_no AND t.from_date < d.to_date AND t.to_date > d.from_date)
ORDER BY e.emp_no ASC"
}
}
filter {
aggregate {
task_id => "%{employee_number}"
code => "
map['employee_number'] = event.get('employee_number')
map['birth_date'] = event.get('birth_date')
map['first_name'] = event.get('first_name')
map['last_name'] = event.get('last_name')
map['gender'] = event.get('gender')
map['hire_date'] = event.get('hire_date')
map['roles'] ||= []
map['roles'] << {
'title.name' => event.get('titlename'),
'title.from_date' => event.get('titlefrom_date'),
'title.to_date' => event.get('titleto_date'),
'department.number' => event.get('departmentnumber'),
'department.name' => event.get('departmentname'),
'department.from_date' => event.get('departmentfrom_date'),
'department.to_date' => event.get('departmentto_date')
}
event.cancel()"
push_previous_map_as_event => true
timeout => 30
}
}
output {
stdout{ codec => rubydebug }
elasticsearch{
action => "index"
index => "employees"
document_type => "employee"
document_id => "%{employee_number}"
hosts => "localhost:9200"
}
}
You can also try to make use of jdbc streaming in logstash filter plugin.
Check this post
Inserting Nested Objects using Logstash
For example, I am taking Stackoverflow Posts and Users as an example. Here Post is parent table and it is associated with Users table on OwnerUserId. So my plugin configuration is
input {
jdbc {
jdbc_driver_library => "/usr/share/logstash/javalib/mssql-jdbc-8.2.2.jre11.jar"
jdbc_driver_class => "com.microsoft.sqlserver.jdbc.SQLServerDriver"
jdbc_connection_string => "jdbc:sqlserver://host.docker.internal;database=StackOverflow2010;user=pavan;password=pavankumar#123"
jdbc_user => "pavan"
jdbc_password => "pavankumar#123"
statement => "select top 500 * from StackOverflow2010.dbo.Posts p "
}
}
filter{
jdbc_streaming {
jdbc_driver_library => "/usr/share/logstash/javalib/mssql-jdbc-8.2.2.jre11.jar"
jdbc_driver_class => "com.microsoft.sqlserver.jdbc.SQLServerDriver"
jdbc_connection_string => "jdbc:sqlserver://host.docker.internal;database=StackOverflow2010;user=pavan;password=pavankumar#123"
jdbc_user => "pavan"
jdbc_password => "pavankumar#123"
statement => "select * from StackOverflow2010.dbo.Users u where u.Id = :owneruserid"
parameters => {"owneruserid" => "owneruserid"}
target => "user_details"
}
}
output {
elasticsearch {
hosts => ["http://elasticsearch:9200", "http://elasticsearch:9200"]
index => "stackoverflow_top_user"
}
stdout {
codec => rubydebug
}
}

How find a nth node value using ruby

I have a JSON response tree like structure
{
"id":""
"node": [
{
"id":""
"node": [
{
"id":""
"node":[]
}
]
}
]
}
How could I get the last id value, it's just example it may contain n number of loops.
h = {
"id" => "1",
"node" => [
{
"id" => "2",
"node" => [
{
"id" => "3",
"node" => []
}
]
}
]
}
▶ λ = ->(h) { h['node'].empty? ? h['id'] : λ.(h['node'].last) }
#⇒ #<Proc:0x00000002f4b490#(pry):130 (lambda)>
▶ λ.(h)
#⇒ "3"
Maybe this method will helps you. You can call recursion method with sub hash.
h = {
"id" => "1",
"node" => [
{
"id" => "2",
"node" => [
{
"id" => "3",
"node" => []
}
]
}
]
}
def get_last_node(h)
if Array === h['node'] && !h['node'].empty?
h['node'].each do |node_h|
id = send(__callee__, node_h)
return id if id
end
nil
else
h['id']
end
end
get_last_node(h)
# => 3
Similar to #mudasobwa's answer:
def get_last_node(h)
h["node"].empty? ? h["id"] : get_last_node(h["node"].first)
end
get_last_node(h)
#=> 3

Resources