Kendo Menu binding menu dynamically via JSON - java

I'm trying to bind the JSON data object retrieved from the servlet.
$("#mainVerticalMenu").kendoMenu({
dataSource : new kendo.data.DataSource({
transport: {
read: {
url: "net/samso/action/MenuAction?func_flag=getMenu&user_id=nexol", // the servlet url
dataType: "json",
}
},
schema: { // describe the result format
model : {
fields : {
text : {
type : "string"
},
value : {
type : "string"
},
subItemList: [{ // Sub item collection
text : {
type : "string"
},
value : {
type : "string"
}
}]
}
}
}
})
});
From the servlet, the JSON format is given as follows:
Hierarchy:
Text
Value
subItemList (ItemObject nested inside the menuitem)
- Text
- Value
Example JSON:
Which ends up looking like:
[{"text":"OuterMenu1","value":"menu1","subItemList":[{"text":"subMenuItem1","value":"subMenu1"},{"text":"subMenuItem2","value":"subMenu2"}]}]
Actual JSON I receive when calling the servlet directly:
[{"text":"Communication","value":"BASE_01","subItemList":[{"text":"상품소개조회","value":"BASE_01"},{"text":"공지사항","value":"BASE_02"},{"text":"의견수렴","value":"BASE_04"},{"text":"사용자관리","value":"BASE_05"},{"text":"받은쪽지","value":"BASE_07"},{"text":"보낸쪽지","value":"BASE_08"},{"text":"자유게시판","value":"BASE_09"},{"text":"매장/마진율 정보","value":"BASE_10"}]},{"text":"매입관리","value":"BUY_01","subItemList":[{"text":"입고/입고반품현황","value":"BUY_01"},{"text":"수평이동요청","value":"BUY_02"},{"text":"수평이동승인/조회","value":"BUY_03"}]},{"text":"판매관리","value":"SALE_01","subItemList":[{"text":"판매및반품등록","value":"SALE_01"},{"text":"판매및반품조회","value":"SALE_02"},{"text":"판매일보","value":"SALE_04"},{"text":"기간별판매현황","value":"SALE_05"},{"text":"판매순위분석","value":"SALE_06"},{"text":"판매순위표","value":"SALE_07"},{"text":"타사등록","value":"SALE_08"},{"text":"타사판매등록","value":"SALE_09"},{"text":"타사판매조회","value":"SALE_10"}]},{"text":"수불관리","value":"SUBUL_01","subItemList":[{"text":"상품주문등록","value":"SUBUL_01"},{"text":"상품주문조회","value":"SUBUL_02"},{"text":"미입고명세서","value":"SUBUL_10"},{"text":"일별수불현황","value":"SUBUL_04"},{"text":"재고현황","value":"SUBUL_05"},{"text":"수불 일/월보","value":"SUBUL_09"},{"text":"품목별수불현황","value":"SUBUL_08"},{"text":"재고조정","value":"SUBUL_11"},{"text":"타매장재고현황","value":"SUBUL_07"}]},{"text":"영업관리","value":"BUSS_01","subItemList":[{"text":"영업판매배치등록","value":"BUSS_01"},{"text":"영업판매조회","value":"BUSS_02"},{"text":"영업주문배치등록","value":"BUSS_03"},{"text":"영업주문조회","value":"BUSS_04"},{"text":"매장별 재고/수불현황","value":"BUSS_05"}]},{"text":"AS관리","value":"AS_01","subItemList":[{"text":"A/S의뢰 관리","value":"AS_01"}]},{"text":"관리자","value":"SUP_06","subItemList":[{"text":"기초코드관리","value":"SUP_06"},{"text":"시스템관리","value":"SUP_05"},{"text":"그룹관리","value":"SUP_02"},{"text":"그룹소속관리","value":"SUP_03"},{"text":"그룹권한관리","value":"SUP_04"},{"text":"매장등록현황","value":"SUP_01"},{"text":"마진율조회","value":"SUP_07"},{"text":"상품코드별권한등록","value":"SUP_08"},{"text":"거래처별상품권한등록","value":"SUP_09"},{"text":"마감현황","value":"SUP_10"},{"text":"SAP송수신기록조회","value":"SUP_12"}]},{"text":"회계","value":"ACCT_01","subItemList":[{"text":"WEB-POS 사용자현황","value":"ACCT_01"},{"text":"WEB-POS 입금등록","value":"ACCT_02"}]}]
I'd like to ask two questions:
The servlet is not being called at all, even though I've explicitly declared the transport URL in the datasource.
Is the above schema correct for declaring outer menu items and nesting items inside them?

The servlet is not being called because Kendo Menu does not define a DataSource for loading its content. BUT that doesn't mean that you cannot do it: yes, you can!
What you should do is:
Define an empty menu.
Define a DataSource.
Trigger manually a read in the DataSource
Append received data to the original menu.
The code:
var menu = $("#menu").kendoMenu({}).data("kendoMenu");
var ds = new kendo.data.DataSource({
transport: {
read: {
url : "menu.json",
dataType: "json"
}
},
schema : {
data: function (data) {
menu.append(data);
}
}
});
ds.read();
About your second question regarding the format of the JSON: replace subItemList by items, that's it. The entries on your JSON would look like:
[
{
"text" : "Communication",
"value" : "BASE_01",
"items": [
{
"text" : "상품소개조회",
"value": "BASE_01"
},
{
"text" : "공지사항",
"value": "BASE_02"
},
{
"text" : "의견수렴",
"value": "BASE_04"
},
{
"text" : "사용자관리",
"value": "BASE_05"
},
{
"text" : "받은쪽지",
"value": "BASE_07"
},
{
"text" : "보낸쪽지",
"value": "BASE_08"
},
{
"text" : "자유게시판",
"value": "BASE_09"
},
{
"text" : "매장/마진율 정보",
"value": "BASE_10"
}
]
},
{
"text" : "매입관리",
"value" : "BUY_01",
"items": [
{
"text" : "입고/입고반품현황",
"value": "BUY_01"
},
{
"text" : "수평이동요청",
"value": "BUY_02"
},
{
"text" : "수평이동승인/조회",
"value": "BUY_03"
}
]
},
{
"text" : "판매관리",
"value" : "SALE_01",
"items": [
{
"text" : "판매및반품등록",
"value": "SALE_01"
},
{
"text" : "판매및반품조회",
"value": "SALE_02"
},
{
"text" : "판매일보",
"value": "SALE_04"
},
{
"text" : "기간별판매현황",
"value": "SALE_05"
},
{
"text" : "판매순위분석",
"value": "SALE_06"
},
{
"text" : "판매순위표",
"value": "SALE_07"
},
{
"text" : "타사등록",
"value": "SALE_08"
},
{
"text" : "타사판매등록",
"value": "SALE_09"
},
{
"text" : "타사판매조회",
"value": "SALE_10"
}
]
},
{
"text" : "수불관리",
"value" : "SUBUL_01",
"items": [
{
"text" : "상품주문등록",
"value": "SUBUL_01"
},
{
"text" : "상품주문조회",
"value": "SUBUL_02"
},
{
"text" : "미입고명세서",
"value": "SUBUL_10"
},
{
"text" : "일별수불현황",
"value": "SUBUL_04"
},
{
"text" : "재고현황",
"value": "SUBUL_05"
},
{
"text" : "수불 일/월보",
"value": "SUBUL_09"
},
{
"text" : "품목별수불현황",
"value": "SUBUL_08"
},
{
"text" : "재고조정",
"value": "SUBUL_11"
},
{
"text" : "타매장재고현황",
"value": "SUBUL_07"
}
]
},
{
"text" : "영업관리",
"value" : "BUSS_01",
"items": [
{
"text" : "영업판매배치등록",
"value": "BUSS_01"
},
{
"text" : "영업판매조회",
"value": "BUSS_02"
},
{
"text" : "영업주문배치등록",
"value": "BUSS_03"
},
{
"text" : "영업주문조회",
"value": "BUSS_04"
},
{
"text" : "매장별 재고/수불현황",
"value": "BUSS_05"
}
]
},
{
"text" : "AS관리",
"value" : "AS_01",
"items": [
{
"text" : "A/S의뢰 관리",
"value": "AS_01"
}
]
},
{
"text" : "관리자",
"value" : "SUP_06",
"items": [
{
"text" : "기초코드관리",
"value": "SUP_06"
},
{
"text" : "시스템관리",
"value": "SUP_05"
},
{
"text" : "그룹관리",
"value": "SUP_02"
},
{
"text" : "그룹소속관리",
"value": "SUP_03"
},
{
"text" : "그룹권한관리",
"value": "SUP_04"
},
{
"text" : "매장등록현황",
"value": "SUP_01"
},
{
"text" : "마진율조회",
"value": "SUP_07"
},
{
"text" : "상품코드별권한등록",
"value": "SUP_08"
},
{
"text" : "거래처별상품권한등록",
"value": "SUP_09"
},
{
"text" : "마감현황",
"value": "SUP_10"
},
{
"text" : "SAP송수신기록조회",
"value": "SUP_12"
}
]
},
{
"text" : "회계",
"value" : "ACCT_01",
"items": [
{
"text" : "WEB-POS 사용자현황",
"value": "ACCT_01"
},
{
"text" : "WEB-POS 입금등록",
"value": "ACCT_02"
}
]
}
]

Related

How to modify JSON with dynamic nesting in Java?

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")));

Elastic search - Java api to search on multiple fields not giving exact results

Am search my input keyword in multiple field using java api QueryBuilders.multiMatchQuery its not giving me exact results. Its giving some random results which is not relavant to my search query.
Please find my code below.
SearchRequest contentSearchRequest = new SearchRequest(ATTACHMENT);
SearchSourceBuilder contentSearchSourceBuilder = new SearchSourceBuilder();
contentSearchRequest.types(TYPE);
MultiMatchQueryBuilder attachmentQB = QueryBuilders.multiMatchQuery(keyword, "attachment.content","catalog_keywords","product_keywords");
contentSearchSourceBuilder.query(attachmentQB);
contentSearchSourceBuilder.size(5);
Please find my mapping details :
PUT document_attachment
{
"settings": {
"analysis": {
"analyzer": {
"custom_analyzer": {
"type": "custom",
"tokenizer": "whitespace",
"char_filter": [
"html_strip"
],
"filter": [
"lowercase",
"asciifolding"
]
},
"product_catalog_keywords_analyzer": {
"type": "custom",
"tokenizer": "whitespace",
"char_filter": [
"html_strip"
],
"filter": [
"lowercase",
"asciifolding"
]
}
}
}
},
"mappings" : {
"doc" : {
"properties" : {
"attachment" : {
"properties" : {
"content" : {
"type" : "text",
"analyzer": "custom_analyzer"
},
"content_length" : {
"type" : "long"
},
"content_type" : {
"type" : "text"
},
"language" : {
"type" : "text"
}
}
},
"fileContent" : {
"type" : "text"
},
"id": {
"type": "long"
},
"catalog_keywords" : {
"type" : "text",
"analyzer": "product_catalog_keywords_analyzer"
},
"product_keywords" : {
"type" : "text",
"analyzer": "product_catalog_keywords_analyzer"
},
}
}
}
}

How to dynamically order search results in elastic search based on a criteria obtained at runtime?

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.

"MapperParsingException[Analyzer [second] not found for field [Name]]"

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"
]
}
}
}
}

ElasticSearch Querying and OR

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.

Categories