I built the structure on cassandra DB to store the time series data of the OS data like services, process and other information. To understand how to works Cassandra about storing JSON data and retrieval the data by CQL queries with condition I prefered to simplify the model. Because in the total model DB I'll have the TYPE more complex than report_object like hashMap of array of hashMap for example:
Type NETSTAT--> Object[n] --> {host:192.168.0.23, protocol: TCP ,LocalAddress : 0.0.0.0}
so the Type NETSTAT will have a list of hashMaps that will contain the fields key -> value.
For simplify I have choosen to show the following schema:
CREATE TYPE report_object (RTIME varchar, RMINORVER int, RUSER varchar, RLANG varchar, RSCRIPT varchar, RMAJORVER int, RHOST varchar, RPATH varchar);
CREATE TABLE test (
REPORTUUID uuid PRIMARY KEY,
report frozen<report_object>);
Inside the table I injectioned the JSON data with the followed query inside java class:
INSERT INTO test JSON '{"REPORTUUID": "9fb21fb9-333e-4017-ab77-0fa6ee1e20e3" ,"REPORT":{"RTIME":"6/MAR/2016 6:0:0 PM","RMINORVER":0,"RUSER":"Administrator","RLANG":"vbs","RSCRIPT":"Main","RMAJORVER":5,"RHOST":"WIN-SAPV9MUEMNS","RPATH":"C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\IXP000.TMP"}}';
I inectioned other data with the query above.
The questions to clarify my concepts are:
- I would like to do the queries with conditions that check inside TYPE defined, is it possible with CQL or is necessary to use spark SQL?
Is design DB model right for the purpose (Because I have passed from RDBMS to DB NoSQL) ?
To be able to query User Defined Type using Cassandra you'll have to create an index first:
CREATE INDEX on test.test(report);
but it allows only a predicate based on a full document:
SELECT * FROM test
WHERE report=fromJson('{"RTIME":"6/MAR/2016 6:0:0 PM","RMINORVER":0,"RUSER":"Administrator","RLANG":"vbs","RSCRIPT":"Main","RMAJORVER":5,"RHOST":"WIN-SAPV9MUEMNS","RPATH":"C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\IXP000.TMP"}');
You'll find more details and explanation in how to filter cassandra query by a field in user defined type
When exposed using Spark these values can be filtered using filter on CassandraTableScanRDD:
val rdd = sc.cassandraTable("test", "test")
rdd.filter(row =>
row.getUDTValue("report").getString("rscript") == "Main")
or where / filter on a DataFrame:
df.where($"report.rscript" === "Main")
Although query like this using Spark a whole table has to be fetched before data can be filtered. While it is not clear what exactly you are trying to achieve but it is rather unlikely this will be an useful structure in general.
Related
I apologize in advance if this is very simple and I am just missing it.
Would any of you know how to put custom attributes as column headers? I currently have a simple opt in survey on connect and I would like to have each of the 4 items as column headers and the score in the table results. I pull the data using an ODBC connection to excel so ideally I would like to just add this on the end of my current table if I can figure out how to do it.
This is how it currently looks in the output
{"effortscore":"5","promoterscore":"5","satisfactionscore":"5","survey_opt_in":"True"}
If you have any links or something that I can follow to try improve my knowledge.
Thanks in advance
There are multiple options to query data in JSON format in Athena, and based on your use case (data source, query frequency, query destination, etc.) you can choose what makes more sense.
String Column + JSON functions
This is usually the most straightforward option and a good starting point. You define the survey_output as a string column, and when you need to extract the specific attributes from the JSON string, you can apply the JSON functions in Trino/Athena: https://trino.io/docs/current/functions/json.html. For example:
SELECT
id,
json_query(
survey_output,
'lax $.satisfactionscore'
) AS satisfactionscore
FROM customers
String Column + JSON functions + View
The following way to simplify access to data without json_query functions is to define a VIEW on that table using the json_query syntax in the VIEW creation. You define the view once by a DBA, and when the users query the data, they see the columns they care about. For example:
CREATE VIEW survey_results AS
SELECT
id,
json_query(
survey_output,
'lax $.satisfactionscore'
) AS satisfactionscore
FROM customers;
With such dynamic view creation, you have more flexibility in what data will be easily exposed to the users.
Create a Table with STRUCT
Another option is to create the external table from the data source (files in S3, for example) with the STRUCT definition.
CREATE EXTERNAL TABLE survey (
id string,
survey_results struct<
effortscore:string,
promoterscore:string,
satisfactionscore:string,
survey_opt_in:string
>
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
LOCATION 's3://<YOUR BUCKET HERE>/<FILES>'
I have a use case to store dynamic JSON objects in a column in Big Query. The schema of the object is dynamically generated by the source and not known beforehand. The number of key value pairs in the object can differ as well, as shown below.
Example JSON objects:
{"Fruit":"Apple","Price":"10","Sale":"No"}
{"Movie":"Avatar","Genre":"Fiction"}
I could achieve the same in Hive by defining the column as map<string, string> object and I could query the data in the column like col_name["Fruit"] or col_name["Movie"] for that corresponding row.
Is there an equivalent way of above usage in Big Query? I came across 'RECORD' data type but the schema needs to be same for all the objects in the column.
Note: Storing the column as string datatype is not an option as the users need to query the data on the keys directly without parsing after retrieving the data.
Storing the data as a JSON string seems to be the only way to implement your requirement, at the moment. As a workaround, you can create a JavaScript UDF that parses the JSON string and extracts the necessary information. Below is a sample UDF.
CREATE TEMP FUNCTION extract_from_json(json STRING, key STRING)
RETURNS STRING
LANGUAGE js AS """
const obj = JSON.parse(json);
return obj[key];
""";
WITH json_table AS (
SELECT '{"Fruit":"Apple","Price":"10","Sale":"No"}' json_data UNION ALL
SELECT '{"Movie":"Avatar","Genre":"Fiction"}' json_data
)
SELECT extract_from_json(json_data, 'Movie') AS photos
FROM json_table
You can also check out the newly introduced JSON data type in BigQuery. The data type offers more flexibility when handling JSON data but please note that the data type is still in preview and is not recommended for production. You will have to enroll in this preview. For more information on working with JSON data, refer to this documentation.
I want filter product by gender(men,women)
gender of the product saved in database within json format like ["\u0622\u0642\u0627\u06cc\u0627\u0646"]
in my controller want get product by gender name
public function index(){
$product = Product::where(['gender' => json_decode('men',true)])
->orderBy('created_at','Desc')->get();
}
how can fetch product that gender is men or women
Some products can be used for both men and women, so I save in Json format
dd from product as you can see gender store in json format:
thanks a lot for your help
Searching values in Json
Mysql
Actually having json data for a column, make it hard for indexing and searching in RDBMS databases like Mariadb, mysql, ....
Key-value No-Sql DBMS
if you use mongo, cockroach, DynoDB, ... they are embracing this approach.
but you would need to redesign all the DB architecture !!!
Postgres
but if you are using Postgres DB it would be fine as long as you use the Jsonb data type for the gender column.
but as i can see your foreign keys as 1,2,3 ..., I assume that you are using mysql maybe.
Redesign DB Schema instead of migrating to Postgres
I would like to recommend to use boolean or enum type column which more suites your scenario, instead of Json.
with boolean columns you can have multiple selected attributes for given data.
like : either "Mardaneh" & "Zananeh" & "Bacheganeh" ...
with the enum you would be sure at DB level that, there is a gender has been selected
in your case I guess two boolean column makes more sense.
I want to create column with type RECORD
I have a STRUCT OR ARRAY(STRUCT)
json
--------
"fruit":[{"apples":"5","oranges":"10"},{"apples":"5","oranges":"4"}]
"fruit":{"apples":"1","oranges":"15"}
"fruit":{"apples":"5","oranges":"1"}
I want to create fruit of RECORD type
fruit RECORD NULLABLE
fruit.apples STRING NULLABLE
fruit.oranges STRING NULLABLE
Using bigquery SQL you can use the following DDL as described in the documentation https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_table_statement
CREATE TABLE mydataset.newtable
(
fruit STRUCT<
apples STRING,
oranges STRING
>
)
You can also use BQ auto-detect feature to create table from a JSON file https://cloud.google.com/bigquery/docs/schema-detect#loading_data_using_schema_auto-detection
I believe the most straightforward way to achieve what you want to do is by using an edited version of the json file you have provided (complying to the rules shown in the Public Docs) and loading your data with auto-detection from the Cloud Console.
If you would like to get the following schema:
fruit RECORD NULLABLE
fruit.apples INTEGER NULLABLE
fruit.oranges INTEGER NULLABLE
You should use the following json file:
{"fruit":{"apples":"5","oranges":"10"}}
{"fruit":{"apples":"5","oranges":"4"}}
{"fruit":{"apples":"1","oranges":"15"}}
{"fruit":{"apples":"5","oranges":"1"}}
On the other hand, if you prefer to get a repeated attribute (since there are two fruit objects in the same row of the example you provided), you would need to use the following file:
{"fruit":[{"apples":"5","oranges":"10"},{"apples":"5","oranges":"4"}]}
{"fruit":{"apples":"1","oranges":"15"}}
{"fruit":{"apples":"5","oranges":"1"}}
This will result in the following schema:
fruit RECORD REPEATED
fruit.apples INTEGER NULLABLE
fruit.oranges INTEGER NULLABLE
Finally, I have noticed that you have specified in the question that you would like instead to get the attributes fruit.apples and fruit.oranges as STRING (which is not straightforward for the auto-detection since the values are numbers such as 5 and 10). In this case you could explicitly create the table with a DDL statement, but I strongly suggest considering turning these fields into a integer if that would still suit your use case scenario.
I have a table in AWS Glue, and the crawler has defined one field as array.
The content is in S3 files that have a json format.
The table is TableA, and the field is members.
There are a lot of other fields such as strings, booleans, doubles, and even structs.
I am able to query them all using a simpel query such as:
SELECT
content.my_boolean,
content.my_string,
content.my_struct.value
FROM schema.tableA;
The issue is when I add content.members into the query.
The error I get is: [Amazon](500310) Invalid operation: schema "content" does not exist.
Content exists because i am able to select other fiels from the main key in the json (content).
Probably is something related with how to perform the query agains array field in Spectrum.
Any idea?
You have to rename the table to extract the fields from the external schema:
SELECT
a.content.my_boolean,
a.content.my_string,
a.content.my_struct.value
FROM schema.tableA a;
I had the same issue on my data, I really don't know why it needs this cast but it works. If you need to access elements of an array you have to explod it like:
SELECT member.<your-field>,
FROM schema.tableA a, a.content.members as member;
Reference
You need to create a Glue Classifier.
Select JSON as Classifier type
and for the JSON Path input the following:
$[*]
then run your crawler. It will infer your schema and populate your table with the correct fields instead of just one big array. Not sure if this was what you were looking for but figured I'd drop this here just in case others had the same problem I had.