I am using QuickBooks reports API and I want to convert the JSON reports to pdf and also do some modifications. Most of the reports (like Balance Sheet) have dynamic nested structure, i.e. the depth of nesting is not static. How can I convert the JSON to Java Objects so that I can work on them. Collectively some rows make sections and a section can contain either rows or sub-sections (This nesting can go deeper). The way to differentiate is the presence of type data or section in the rows value.
I was thinking on lines of writing a recursive function, which goes through the rows until it finds a row with type=data. But I am looking for something better.
Link to QuickBooks Documentation.
This is the sample JSON.
{
"Header": {
"ReportName": "BalanceSheet",
"Option": [
{
"Name": "AccountingStandard",
"Value": "GAAP"
},
{
"Name": "NoReportData",
"Value": "false"
}
],
"DateMacro": "this calendar year-to-date",
"ReportBasis": "Accrual",
"StartPeriod": "2016-01-01",
"Currency": "USD",
"EndPeriod": "2016-10-31",
"Time": "2016-10-31T09:42:21-07:00",
"SummarizeColumnsBy": "Total"
},
"Rows": {
"Row": [
{
"Header": {
"ColData": [
{
"value": "ASSETS"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"Header": {
"ColData": [
{
"value": "Current Assets"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"Header": {
"ColData": [
{
"value": "Bank Accounts"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "35",
"value": "Checking"
},
{
"value": "1350.55"
}
],
"type": "Data"
},
{
"ColData": [
{
"id": "36",
"value": "Savings"
},
{
"value": "800.00"
}
],
"type": "Data"
}
]
},
"type": "Section",
"group": "BankAccounts",
"Summary": {
"ColData": [
{
"value": "Total Bank Accounts"
},
{
"value": "2150.55"
}
]
}
},
{
"Header": {
"ColData": [
{
"value": "Accounts Receivable"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "84",
"value": "Accounts Receivable (A/R)"
},
{
"value": "6383.12"
}
],
"type": "Data"
}
]
},
"type": "Section",
"group": "AR",
"Summary": {
"ColData": [
{
"value": "Total Accounts Receivable"
},
{
"value": "6383.12"
}
]
}
},
{
"Header": {
"ColData": [
{
"value": "Other current assets"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "81",
"value": "Inventory Asset"
},
{
"value": "596.25"
}
],
"type": "Data"
},
{
"ColData": [
{
"id": "4",
"value": "Undeposited Funds"
},
{
"value": "2117.52"
}
],
"type": "Data"
}
]
},
"type": "Section",
"group": "OtherCurrentAssets",
"Summary": {
"ColData": [
{
"value": "Total Other current assets"
},
{
"value": "2713.77"
}
]
}
}
]
},
"type": "Section",
"group": "CurrentAssets",
"Summary": {
"ColData": [
{
"value": "Total Current Assets"
},
{
"value": "11247.44"
}
]
}
},
{
"Header": {
"ColData": [
{
"value": "Fixed Assets"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"Header": {
"ColData": [
{
"id": "37",
"value": "Truck"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "38",
"value": "Original Cost"
},
{
"value": "13495.00"
}
],
"type": "Data"
}
]
},
"type": "Section",
"Summary": {
"ColData": [
{
"value": "Total Truck"
},
{
"value": "13495.00"
}
]
}
}
]
},
"type": "Section",
"group": "FixedAssets",
"Summary": {
"ColData": [
{
"value": "Total Fixed Assets"
},
{
"value": "13495.00"
}
]
}
}
]
},
"type": "Section",
"group": "TotalAssets",
"Summary": {
"ColData": [
{
"value": "TOTAL ASSETS"
},
{
"value": "24742.44"
}
]
}
},
{
"Header": {
"ColData": [
{
"value": "LIABILITIES AND EQUITY"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"Header": {
"ColData": [
{
"value": "Liabilities"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"Header": {
"ColData": [
{
"value": "Current Liabilities"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"Header": {
"ColData": [
{
"value": "Accounts Payable"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "33",
"value": "Accounts Payable (A/P)"
},
{
"value": "1984.17"
}
],
"type": "Data"
}
]
},
"type": "Section",
"group": "AP",
"Summary": {
"ColData": [
{
"value": "Total Accounts Payable"
},
{
"value": "1984.17"
}
]
}
},
{
"Header": {
"ColData": [
{
"value": "Credit Cards"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "41",
"value": "Mastercard"
},
{
"value": "157.72"
}
],
"type": "Data"
}
]
},
"type": "Section",
"group": "CreditCards",
"Summary": {
"ColData": [
{
"value": "Total Credit Cards"
},
{
"value": "157.72"
}
]
}
},
{
"Header": {
"ColData": [
{
"value": "Other Current Liabilities"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "89",
"value": "Arizona Dept. of Revenue Payable"
},
{
"value": "4.55"
}
],
"type": "Data"
},
{
"ColData": [
{
"id": "90",
"value": "Board of Equalization Payable"
},
{
"value": "401.98"
}
],
"type": "Data"
},
{
"ColData": [
{
"id": "43",
"value": "Loan Payable"
},
{
"value": "4000.00"
}
],
"type": "Data"
}
]
},
"type": "Section",
"group": "OtherCurrentLiabilities",
"Summary": {
"ColData": [
{
"value": "Total Other Current Liabilities"
},
{
"value": "4406.53"
}
]
}
}
]
},
"type": "Section",
"group": "CurrentLiabilities",
"Summary": {
"ColData": [
{
"value": "Total Current Liabilities"
},
{
"value": "6548.42"
}
]
}
},
{
"Header": {
"ColData": [
{
"value": "Long-Term Liabilities"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "44",
"value": "Notes Payable"
},
{
"value": "25000.00"
}
],
"type": "Data"
}
]
},
"type": "Section",
"group": "LongTermLiabilities",
"Summary": {
"ColData": [
{
"value": "Total Long-Term Liabilities"
},
{
"value": "25000.00"
}
]
}
}
]
},
"type": "Section",
"group": "Liabilities",
"Summary": {
"ColData": [
{
"value": "Total Liabilities"
},
{
"value": "31548.42"
}
]
}
},
{
"Header": {
"ColData": [
{
"value": "Equity"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "34",
"value": "Opening Balance Equity"
},
{
"value": "-9337.50"
}
],
"type": "Data"
},
{
"ColData": [
{
"id": "2",
"value": "Retained Earnings"
},
{
"value": "91.25"
}
],
"type": "Data"
},
{
"ColData": [
{
"value": "Net Income"
},
{
"value": "2440.27"
}
],
"type": "Data",
"group": "NetIncome"
}
]
},
"type": "Section",
"group": "Equity",
"Summary": {
"ColData": [
{
"value": "Total Equity"
},
{
"value": "-6805.98"
}
]
}
}
]
},
"type": "Section",
"group": "TotalLiabilitiesAndEquity",
"Summary": {
"ColData": [
{
"value": "TOTAL LIABILITIES AND EQUITY"
},
{
"value": "24742.44"
}
]
}
}
]
},
"Columns": {
"Column": [
{
"ColType": "Account",
"ColTitle": "",
"MetaData": [
{
"Name": "ColKey",
"Value": "account"
}
]
},
{
"ColType": "Money",
"ColTitle": "Total",
"MetaData": [
{
"Name": "ColKey",
"Value": "total"
}
]
}
]
}
}
JSON Object can ALWAYS be converted to Map. JSON List can ALWAYS be converted to List. Object in those structures can be among other things Map<String, Object> or List<Object>. So you get your multi-nested structure with no depth limitation. To convert JSON to Java class and Java class to JSON is called deserialization and serialization respectively. Today there are 2 major known libraries that do that (and much more) for you. One is Jackson-JSON (otherwise known as "Fast XML" - go figure...) and the other is GSON - a Google library based on Jackson-JSON but also supports passing binary objects. I personally prefer Jackson-JSON, but that's the matter of personal preference. For GSON library look here. For Jackson look here. For Maven artifacts for Jackson look here. If you choose to work with Jackson, then the main class that you need is ObjectMapper.
Start from looking into methods readValue() and writeValue(). Look for endless examples on the web on how to work with it. This should give you a good start
Use reflection apis in java to create your custom type:
Type myType = new TypeToken<ArrayList<HashMap<String, Object>>() {}.getType();
Then use Gson api to convert the JSON into the Java object:
List<Map<String, Object>> outputList = new Gson().fromJson(inputJSONObject, myType);
And then you can iterate over your list and create some consumers to get the sub-objects out of it:
UnaryOperator<Map<String, Object>> subMap = s -> {
Map<String, Object> map = new HashMap<>();
map.put("Header", s.remove("Header"));
...
...
return map;
};
This is a super nested JSON object. This makes it complicated to do in Java and hard to troubleshoot. Nevertheless it can be done.
You could use BSON to load your code and then parse out the values.
Start by importing your libraries.
//import java.util.ArrayList;
//import org.bson.Document;
Parse your JSON into a BSON Document
Document root = Document.parse("{ \"Header\" : { \"ReportName\" : \"BalanceSheet\", \"Option\" : [{ \"Name\" : \"AccountingStandard\", \"Value\" : \"GAAP\" }, { \"Name\" : \"NoReportData\", \"Value\" : \"false\" }], \"DateMacro\" : \"this calendar year-to-date\", \"ReportBasis\" : \"Accrual\", \"StartPeriod\" : \"2016-01-01\", \"Currency\" : \"USD\", \"EndPeriod\" : \"2016-10-31\", \"Time\" : \"2016-10-31T09:42:21-07:00\", \"SummarizeColumnsBy\" : \"Total\" }, \"Rows\" : { \"Row\" : [{ \"Header\" : { \"ColData\" : [{ \"value\" : \"ASSETS\" }, { \"value\" : \"\" }] }, \"Rows\" : { \"Row\" : [{ \"Header\" : { \"ColData\" : [{ \"value\" : \"Current Assets\" }, { \"value\" : \"\" }] }, \"Rows\" : { \"Row\" : [{ \"Header\" : { \"ColData\" : [{ \"value\" : \"Bank Accounts\" }, { \"value\" : \"\" }] }, \"Rows\" : { \"Row\" : [{ \"ColData\" : [{ \"id\" : \"35\", \"value\" : \"Checking\" }, { \"value\" : \"1350.55\" }], \"type\" : \"Data\" }, { \"ColData\" : [{ \"id\" : \"36\", \"value\" : \"Savings\" }, { \"value\" : \"800.00\" }], \"type\" : \"Data\" }] }, \"type\" : \"Section\", \"group\" : \"BankAccounts\", \"Summary\" : { \"ColData\" : [{ \"value\" : \"Total Bank Accounts\" }, { \"value\" : \"2150.55\" }] } }, { \"Header\" : { \"ColData\" : [{ \"value\" : \"Accounts Receivable\" }, { \"value\" : \"\" }] }, \"Rows\" : { \"Row\" : [{ \"ColData\" : [{ \"id\" : \"84\", \"value\" : \"Accounts Receivable (A/R)\" }, { \"value\" : \"6383.12\" }], \"type\" : \"Data\" }] }, \"type\" : \"Section\", \"group\" : \"AR\", \"Summary\" : { \"ColData\" : [{ \"value\" : \"Total Accounts Receivable\" }, { \"value\" : \"6383.12\" }] } }, { \"Header\" : { \"ColData\" : [{ \"value\" : \"Other current assets\" }, { \"value\" : \"\" }] }, \"Rows\" : { \"Row\" : [{ \"ColData\" : [{ \"id\" : \"81\", \"value\" : \"Inventory Asset\" }, { \"value\" : \"596.25\" }], \"type\" : \"Data\" }, { \"ColData\" : [{ \"id\" : \"4\", \"value\" : \"Undeposited Funds\" }, { \"value\" : \"2117.52\" }], \"type\" : \"Data\" }] }, \"type\" : \"Section\", \"group\" : \"OtherCurrentAssets\", \"Summary\" : { \"ColData\" : [{ \"value\" : \"Total Other current assets\" }, { \"value\" : \"2713.77\" }] } }] }, \"type\" : \"Section\", \"group\" : \"CurrentAssets\", \"Summary\" : { \"ColData\" : [{ \"value\" : \"Total Current Assets\" }, { \"value\" : \"11247.44\" }] } }, { \"Header\" : { \"ColData\" : [{ \"value\" : \"Fixed Assets\" }, { \"value\" : \"\" }] }, \"Rows\" : { \"Row\" : [{ \"Header\" : { \"ColData\" : [{ \"id\" : \"37\", \"value\" : \"Truck\" }, { \"value\" : \"\" }] }, \"Rows\" : { \"Row\" : [{ \"ColData\" : [{ \"id\" : \"38\", \"value\" : \"Original Cost\" }, { \"value\" : \"13495.00\" }], \"type\" : \"Data\" }] }, \"type\" : \"Section\", \"Summary\" : { \"ColData\" : [{ \"value\" : \"Total Truck\" }, { \"value\" : \"13495.00\" }] } }] }, \"type\" : \"Section\", \"group\" : \"FixedAssets\", \"Summary\" : { \"ColData\" : [{ \"value\" : \"Total Fixed Assets\" }, { \"value\" : \"13495.00\" }] } }] }, \"type\" : \"Section\", \"group\" : \"TotalAssets\", \"Summary\" : { \"ColData\" : [{ \"value\" : \"TOTAL ASSETS\" }, { \"value\" : \"24742.44\" }] } }, { \"Header\" : { \"ColData\" : [{ \"value\" : \"LIABILITIES AND EQUITY\" }, { \"value\" : \"\" }] }, \"Rows\" : { \"Row\" : [{ \"Header\" : { \"ColData\" : [{ \"value\" : \"Liabilities\" }, { \"value\" : \"\" }] }, \"Rows\" : { \"Row\" : [{ \"Header\" : { \"ColData\" : [{ \"value\" : \"Current Liabilities\" }, { \"value\" : \"\" }] }, \"Rows\" : { \"Row\" : [{ \"Header\" : { \"ColData\" : [{ \"value\" : \"Accounts Payable\" }, { \"value\" : \"\" }] }, \"Rows\" : { \"Row\" : [{ \"ColData\" : [{ \"id\" : \"33\", \"value\" : \"Accounts Payable (A/P)\" }, { \"value\" : \"1984.17\" }], \"type\" : \"Data\" }] }, \"type\" : \"Section\", \"group\" : \"AP\", \"Summary\" : { \"ColData\" : [{ \"value\" : \"Total Accounts Payable\" }, { \"value\" : \"1984.17\" }] } }, { \"Header\" : { \"ColData\" : [{ \"value\" : \"Credit Cards\" }, { \"value\" : \"\" }] }, \"Rows\" : { \"Row\" : [{ \"ColData\" : [{ \"id\" : \"41\", \"value\" : \"Mastercard\" }, { \"value\" : \"157.72\" }], \"type\" : \"Data\" }] }, \"type\" : \"Section\", \"group\" : \"CreditCards\", \"Summary\" : { \"ColData\" : [{ \"value\" : \"Total Credit Cards\" }, { \"value\" : \"157.72\" }] } }, { \"Header\" : { \"ColData\" : [{ \"value\" : \"Other Current Liabilities\" }, { \"value\" : \"\" }] }, \"Rows\" : { \"Row\" : [{ \"ColData\" : [{ \"id\" : \"89\", \"value\" : \"Arizona Dept. of Revenue Payable\" }, { \"value\" : \"4.55\" }], \"type\" : \"Data\" }, { \"ColData\" : [{ \"id\" : \"90\", \"value\" : \"Board of Equalization Payable\" }, { \"value\" : \"401.98\" }], \"type\" : \"Data\" }, { \"ColData\" : [{ \"id\" : \"43\", \"value\" : \"Loan Payable\" }, { \"value\" : \"4000.00\" }], \"type\" : \"Data\" }] }, \"type\" : \"Section\", \"group\" : \"OtherCurrentLiabilities\", \"Summary\" : { \"ColData\" : [{ \"value\" : \"Total Other Current Liabilities\" }, { \"value\" : \"4406.53\" }] } }] }, \"type\" : \"Section\", \"group\" : \"CurrentLiabilities\", \"Summary\" : { \"ColData\" : [{ \"value\" : \"Total Current Liabilities\" }, { \"value\" : \"6548.42\" }] } }, { \"Header\" : { \"ColData\" : [{ \"value\" : \"Long-Term Liabilities\" }, { \"value\" : \"\" }] }, \"Rows\" : { \"Row\" : [{ \"ColData\" : [{ \"id\" : \"44\", \"value\" : \"Notes Payable\" }, { \"value\" : \"25000.00\" }], \"type\" : \"Data\" }] }, \"type\" : \"Section\", \"group\" : \"LongTermLiabilities\", \"Summary\" : { \"ColData\" : [{ \"value\" : \"Total Long-Term Liabilities\" }, { \"value\" : \"25000.00\" }] } }] }, \"type\" : \"Section\", \"group\" : \"Liabilities\", \"Summary\" : { \"ColData\" : [{ \"value\" : \"Total Liabilities\" }, { \"value\" : \"31548.42\" }] } }, { \"Header\" : { \"ColData\" : [{ \"value\" : \"Equity\" }, { \"value\" : \"\" }] }, \"Rows\" : { \"Row\" : [{ \"ColData\" : [{ \"id\" : \"34\", \"value\" : \"Opening Balance Equity\" }, { \"value\" : \"-9337.50\" }], \"type\" : \"Data\" }, { \"ColData\" : [{ \"id\" : \"2\", \"value\" : \"Retained Earnings\" }, { \"value\" : \"91.25\" }], \"type\" : \"Data\" }, { \"ColData\" : [{ \"value\" : \"Net Income\" }, { \"value\" : \"2440.27\" }], \"type\" : \"Data\", \"group\" : \"NetIncome\" }] }, \"type\" : \"Section\", \"group\" : \"Equity\", \"Summary\" : { \"ColData\" : [{ \"value\" : \"Total Equity\" }, { \"value\" : \"-6805.98\" }] } }] }, \"type\" : \"Section\", \"group\" : \"TotalLiabilitiesAndEquity\", \"Summary\" : { \"ColData\" : [{ \"value\" : \"TOTAL LIABILITIES AND EQUITY\" }, { \"value\" : \"24742.44\" }] } }] }, \"Columns\" : { \"Column\" : [{ \"ColType\" : \"Account\", \"ColTitle\" : \"\", \"MetaData\" : [{ \"Name\" : \"ColKey\", \"Value\" : \"account\" }] }, { \"ColType\" : \"Money\", \"ColTitle\" : \"Total\", \"MetaData\" : [{ \"Name\" : \"ColKey\", \"Value\" : \"total\" }] }] } }");
You can then call out the values using the following syntax. For the arrays you can iterate through the number of values. In order for this to work you need to know what the values are being returned as (I.E. Int, String, or Document) . BSON returns the values as an "Object" so you will have to cast the value. For example: (String) bson.get("field"). This JSON is super large. Here are some examples of how to parse in a single line.
System.out.println(((String)((Document)root.get("Header")).get("ReportName")));
System.out.println(((String)((Document)((ArrayList)((Document)root.get("Header")).get("Option")).get(0)).get("Name")));
System.out.println(((String)((Document)((ArrayList)((Document)root.get("Header")).get("Option")).get(0)).get("Value")));
System.out.println(((String)((Document)root.get("Header")).get("DateMacro")));
System.out.println(((String)((Document)root.get("Header")).get("ReportBasis")));
System.out.println(((String)((Document)root.get("Header")).get("StartPeriod")));
System.out.println(((String)((Document)root.get("Header")).get("Currency")));
System.out.println(((String)((Document)root.get("Header")).get("EndPeriod")));
System.out.println(((String)((Document)root.get("Header")).get("Time")));
System.out.println(((String)((Document)root.get("Header")).get("SummarizeColumnsBy")));
System.out.println(((String)((Document)((ArrayList)((Document)((Document)((ArrayList)((Document)root.get("Rows")).get("Row")).get(0)).get("Header")).get("ColData")).get(0)).get("value")));
System.out.println(((String)((Document)((ArrayList)((Document)((Document)((ArrayList)((Document)((Document)((ArrayList)((Document)root.get("Rows")).get("Row")).get(0)).get("Rows")).get("Row")).get(0)).get("Header")).get("ColData")).get(0)).get("value")));
System.out.println(((String)((Document)((ArrayList)((Document)((Document)((ArrayList)((Document)((Document)((ArrayList)((Document)((Document)((ArrayList)((Document)root.get("Rows")).get("Row")).get(0)).get("Rows")).get("Row")).get(0)).get("Rows")).get("Row")).get(0)).get("Header")).get("ColData")).get(0)).get("value")));
System.out.println(((String)((Document)((ArrayList)((Document)((ArrayList)((Document)((Document)((ArrayList)((Document)((Document)((ArrayList)((Document)((Document)((ArrayList)((Document)root.get("Rows")).get("Row")).get(0)).get("Rows")).get("Row")).get(0)).get("Rows")).get("Row")).get(0)).get("Rows")).get("Row")).get(0)).get("ColData")).get(0)).get("id")));
System.out.println(((String)((Document)((ArrayList)((Document)((ArrayList)((Document)((Document)((ArrayList)((Document)((Document)((ArrayList)((Document)((Document)((ArrayList)((Document)root.get("Rows")).get("Row")).get(0)).get("Rows")).get("Row")).get(0)).get("Rows")).get("Row")).get(0)).get("Rows")).get("Row")).get(0)).get("ColData")).get(0)).get("value")));
System.out.println(((String)((Document)((ArrayList)((Document)((ArrayList)((Document)root.get("Columns")).get("Column")).get(1)).get("MetaData")).get(0)).get("Name")));
System.out.println(((String)((Document)((ArrayList)((Document)((ArrayList)((Document)root.get("Columns")).get("Column")).get(1)).get("MetaData")).get(0)).get("Value")));
We have six categories event_rule_1 to event_rule_6, each can have one priority i.e. High, Medium, Low
I want to show search results based on a priority, Where the priority data is present in the database.
Current approach:
I was fetching the priority from the database and applying on the query i.e as a boost
For High I am giving a boost of 3, Medium boost of 2 and Low a boost of 1.
like below
GET /<index_name>/_search
{
"from" : 0,
"size" : 200,
"query" : {
"bool" : {
"must" : [ {
"term" : {
"fleet_id" : 1
}
}, {
"exists" : {
"field" : "result"
}
}, {
"terms" : {
"state" : [ "active", "viewed" ]
}
} ],
"should" : [ {
"match" : {
"alert_code" : {
"query" : "event_rule_1",
"type" : "boolean",
"boost" : 3.0
}
}
}, {
"match" : {
"alert_code" : {
"query" : "event_rule_2",
"type" : "boolean",
"boost" : 3.0
}
}
}, {
"match" : {
"alert_code" : {
"query" : "event_rule_3",
"type" : "boolean",
"boost" : 3.0
}
}
}, {
"match" : {
"alert_code" : {
"query" : "event_rule_4",
"type" : "boolean",
"boost" : 2.0
}
}
}, {
"match" : {
"alert_code" : {
"query" : "event_rule_5",
"type" : "boolean",
"boost" : 1.0
}
}
}, {
"match" : {
"alert_code" : {
"query" : "event_rule_6",
"type" : "boolean",
"boost" : 1.0
}
}
} ]
}
}
}
But this approach does not seem to work, When I tested with different boost values.
Is there something wrong with this approach? Any suggestions on how to accomplish this in elastic search?
ES schema:
Updated json schema
PUT /schema
{
"alert": {
"properties": {
"id": {
"type": "string",
"index": "not_analyzed"
},
"alert_id": {
"type": "string",
"index": "not_analyzed"
},
"fleet_id": {
"type": "long",
"index": "not_analyzed"
},
"truck_id": {
"type": "long",
"index": "no"
},
"alert_code": {
"type": "string",
"index": "not_analyzed"
},
"alert_desc": {
"type": "string",
"index": "no"
},
"location": {
"type": "string",
"index": "no"
},
"inspected_by": {
"type": "string",
"index": "no"
},
"unit_id": {
"type": "string",
"index": "not_analyzed"
},
"comment": {
"type": "string",
"index": "not_analyzed"
},
"alert_on": {
"type": "date",
"format": "epoch_millis",
"index": "not_analyzed"
},
"is_flagged": {
"type": "boolean",
"index": "no"
},
"make": {
"type": "string",
"index": "no"
},
"model": {
"type": "string",
"index": "no"
},
"year": {
"type": "string",
"index": "no"
},
"axle_config_id": {
"type": "long",
"index": "no"
},
"state": {
"type": "string",
"index": "not_analyzed"
},
"viewed_on": {
"type": "date",
"format": "epoch_millis",
"index": "not_analyzed"
},
"flagged_on": {
"type": "date",
"format": "epoch_millis",
"index": "not_analyzed"
},
"dismissed_on": {
"type": "date",
"format": "epoch_millis",
"index": "not_analyzed"
}
}
}
}
What was the problem with the results?
Default order by is score, so the boost was a great idea, and this should work.
Used a functional score query to implement custom ordering
GET /schema_name/_search
{
"from": 0,
"size": 200,
"query": {
"function_score": {
"query": {
"match_all": {}
},
"boost": "5",
"functions": [{
"filter": {
"term": {
"alert_code": "event_rule_1"
}
},
"weight": 50
},
{
"filter": {
"term": {
"alert_code": "event_rule_2"
}
},
"weight": 30
},
{
"filter": {
"term": {
"alert_code": "event_rule_3"
}
},
"weight": 10
},
{
"filter": {
"term": {
"alert_code": "event_rule_4"
}
},
"weight": 10
},
{
"filter": {
"term": {
"alert_code": "event_rule_5"
}
},
"weight": 50
},
{
"filter": {
"term": {
"alert_code": "event_rule_6"
}
},
"weight": 50
}
],
"max_boost": 50,
"score_mode": "max",
"boost_mode": "replace",
"min_score": 0
}
}
}
Weight is added to the functions at run-time depending on the configurations that is saved in the database.
The parameter boost_mode is set to replace i.e. only function score is used, the query score is ignored.
PS: Had to choose this approach because changing boost in the query didn't give consistent results as the query results depended not only on boost value but also on several other scores.
I have created an index in Elasticsearch with the following settings:
{
"my_index" : {
"aliases" : { },
"mappings" : { },
"settings" : {
"index" : {
"creation_date" : "1461229073677",
"uuid" : "7-TECarfRs6XO8yZE7SeWA",
"number_of_replicas" : "1",
"number_of_shards" : "5",
"version" : {
"created" : "1040599"
},
"settings" : {
"analysis" : {
"analyzer" : {
"second" : {
"type" : "custom",
"filter" : [ "lowercase", "synonym" ],
"tokenizer" : "standard"
}
},
"filter" : {
"synonym" : {
"type" : "synonym",
"synonyms" : [ "i pad => ipad", "smart phone => smartphone" ]
}
}
}
}
}
},
"warmers" : { }
}
}
Now what I m trying to do is to set the mappings using the following code:
PutMapping putMapping = new PutMapping.Builder(
"my_index",
"my_index_type",
"{ \"properties\" : { \"Name\" : {\"type\" : \"string\", \"analyzer\" : \"second\"} } }"
).build();
JestResult result = client.execute(createIndex);
result = client.execute(putMapping);
EDIT
The code I m using to create the index is:
CreateIndex createIndex = new CreateIndex.Builder(indexName)
.settings(
ImmutableSettings.builder()
.loadFromClasspath(
"settings.json"
).build().getAsMap()
).build();
JestResult result = client.execute(createIndex);
and the settings.json looks like this:
{
"settings": {
"analysis": {
"analyzer": {
"second": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"synonym"
]
}
},
"filter": {
"synonym" : {
"type" : "synonym",
"synonyms" : [
"i pad => ipad",
"smart phone => smartphone",
"i phone => iphone"
]
}
}
}
}
}
However I keep getting the following error:
"MapperParsingException[Analyzer [second] not found for field [message]]"
I am able to set the mapping if I remove the "analyzer". So it seems that I have two times the "settings" section, but no matter how I structure the "settings.json" file I keep getting these two sections. I looked into the examples specified in JEST page but didnt help me. https://github.com/searchbox-io/Jest/blob/master/jest/README.md
Any ideas guys?
The settings you're using are not properly defined, i.e. you have two imbricated settings sections, the index settings should look like this instead:
{
"my_index": {
"aliases": {},
"mappings": {},
"settings": {
"index": {
"number_of_replicas": "1",
"number_of_shards": "5"
},
"analysis": {
"analyzer": {
"second": {
"type": "custom",
"filter": [
"lowercase",
"synonym"
],
"tokenizer": "standard"
}
},
"filter": {
"synonym": {
"type": "synonym",
"synonyms": [
"i pad => ipad",
"smart phone => smartphone"
]
}
}
}
},
"warmers": {}
}
}
UPDATE
Your settings.json file simply needs to contain the following:
{
"analysis": {
"analyzer": {
"second": {
"type": "custom",
"filter": [
"lowercase",
"synonym"
],
"tokenizer": "standard"
}
},
"filter": {
"synonym": {
"type": "synonym",
"synonyms": [
"i pad => ipad",
"smart phone => smartphone"
]
}
}
}
}
Here's my mapping
{
"app" : {
"mappings" : {
"patient" : {
"properties" : {
"LastName" : {
"type" : "string"
},
"consultations" : {
"type" : "nested",
"properties" : {
"deleted" : {
"type" : "boolean"
},
"diagnosis" : {
"type" : "string"
},
"documentDate" : {
"type" : "date",
"format" : "dateOptionalTime"
},
"firstName" : {
"type" : "string"
},
"lastName" : {
"type" : "string"
},
"middleName" : {
"type" : "string"
},
"prescriptions" : {
"type" : "string"
}
}
},
"firstName" : {
"type" : "string"
},
"gender" : {
"type" : "string"
},
"id" : {
"type" : "string",
"index" : "not_analyzed"
},
"lastName" : {
"type" : "string"
},
"middleName" : {
"type" : "string"
},
"owner" : {
"type" : "string",
"index" : "not_analyzed"
},
"patientPin" : {
"type" : "string"
}
}
}
}
}
}
Then let's say I have this data
{
"id":"21",
"firstName":"Scrappy",
"patientPin":"2012010000000021",
"middleName":"D",
"consultations":[
{
"id":null,
"prescriptions":[
"GADOTERIC Acid DOTAREM"
],
"diagnosis":[
"Kawasaki's Disease",
"Alcohol Intoxication"
],
"documentDate":"2014-07-31T13:19:00.000+08:00",
"deleted":false,
"lastName":"Doo",
"firstName":"Scrappy",
"middleName":"D"
}
],
"owner":"TENANT1",
"gender":"FEMALE",
"lastName":"Doo"
}
{
"id":"100066",
"firstName":"Kyel ",
"patientPin":"201408000001",
"middleName":"John ",
"consultations":[
{
"id":null,
"prescriptions":[
],
"diagnosis":[
"headache"
],
"documentDate":"2014-08-05T10:10:00.000+08:00",
"deleted":false,
"lastName":"David",
"firstName":"Mika",
"middleName":"John "
}
],
"owner":"TENANT1",
"gender":"MALE",
"lastName":"David"
}
How do I query patients that has consultations that has a "headache" OR "Alcohol Intoxication"?
For your result I am suggesting you to use filter.
You can achieve this using,
For or, terms filter match document with any of value provided (which means does or for values)
client.prepareSearch("app").setTypes("patient").setPostFilter(
FilterBuilders.termsFilter("consultations.diagnosis","headache","Alcohol Intoxication")
);
For and,
client.prepareSearch("app").setTypes("patient").setPostFilter(
FilterBuilders.andFilter(
FilterBuilders.termsFilter("consultations.diagnosis","headache"),
FilterBuilders.termsFilter("consultations.diagnosis","Alcohol Intoxication")
)
);
For this, Any value you want to filter should be index : not_analyzed .
try learning elasticsearch.