Skip to content

Commit 4a7fdb1

Browse files
[ZEPPELIN-6131] Update Interpreter to Store Values as Integers When Applicable
### What is this PR for? There was an issue where the port was treated as a string and included `.0` when modifying the port of the Elasticsearch interpreter. ### What type of PR is it? Bug Fix ### Todos * [x] - Modified HttpBasedClient.java file ### What is the Jira issue? * https://issues.apache.org/jira/projects/ZEPPELIN/issues/ZEPPELIN-6131 ### How should this be tested? * Zeppelin project build and run ```bash ./mvnw clean package -DskipTests ``` * Add a test index and test data to Elasticsearch ```bash # Create an index curl -X PUT "http://localhost:9200/customer?pretty" # Create a document curl -X \ PUT "localhost:9200/customer/_doc/1" \ -H 'Content-Type: application/json' \ -d' { "field_1": "value_1" }' ``` * Modify the Elasticsearch interpreter type and port elasticsearch.client.type: transport -> http elasticsearch.port: 9300 -> 9200 * Previous configuration <img width="1228" alt="image" src="https://github.com/user-attachments/assets/aab69016-b982-4817-8d72-68186fdd45b8"> * New configuration <img width="1219" alt="image" src="https://github.com/user-attachments/assets/a9c44503-1ed1-43c0-89f9-19b92a1ac1e0"> * Create a Zeppelin notebook and execute a paragraph ```bash %elasticsearch get /customer/_doc/1 ``` * Result before modification - Error occurred <img width="942" alt="image" src="https://github.com/user-attachments/assets/00d5db2f-e1dd-46bf-96d9-eb2eb1d88072"> ```bash org.apache.zeppelin.interpreter.InterpreterException: java.lang.NumberFormatException: For input string: "9200.0" at org.apache.zeppelin.interpreter.LazyOpenInterpreter.open(LazyOpenInterpreter.java:77) at org.apache.zeppelin.interpreter.remote.RemoteInterpreterServer$InterpretJob.jobRun(RemoteInterpreterServer.java:808) at org.apache.zeppelin.interpreter.remote.RemoteInterpreterServer$InterpretJob.jobRun(RemoteInterpreterServer.java:716) at org.apache.zeppelin.scheduler.Job.run(Job.java:187) at org.apache.zeppelin.scheduler.AbstractScheduler.runJob(AbstractScheduler.java:136) at org.apache.zeppelin.scheduler.FIFOScheduler.lambda$runJobInScheduler$0(FIFOScheduler.java:42) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:829) Caused by: java.lang.NumberFormatException: For input string: "9200.0" at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.base/java.lang.Integer.parseInt(Integer.java:652) at java.base/java.lang.Integer.parseInt(Integer.java:770) at org.apache.zeppelin.elasticsearch.client.HttpBasedClient.<init>(HttpBasedClient.java:67) at org.apache.zeppelin.elasticsearch.ElasticsearchInterpreter.open(ElasticsearchInterpreter.java:136) at org.apache.zeppelin.interpreter.LazyOpenInterpreter.open(LazyOpenInterpreter.java:71) ... 8 more ``` * Result after modification <img width="500" alt="image" src="https://github.com/user-attachments/assets/2634216c-ed42-4a1e-8c6d-d3bb378365fa"> ### Screenshots (if appropriate) * Refer to the above content ### Questions: * Does the license files need to update? No. * Is there breaking changes for older versions? No. * Does this needs documentation? No. Closes #4878 from ParkGyeongTae/fix-elasticsearch-port-string-handling. Signed-off-by: Philipp Dallig <[email protected]>
1 parent ce04862 commit 4a7fdb1

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed

zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/UpdateInterpreterSettingRequest.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,55 @@ public UpdateInterpreterSettingRequest(Map<String, InterpreterProperty> properti
3939
this.option = option;
4040
}
4141

42+
/**
43+
* Retrieves the properties of the interpreter and, if the property type is "number"
44+
* and its value is a double that represents a whole number, converts that value to an integer.
45+
*
46+
* @return A map of the interpreter's properties with possible modifications to the numeric properties.
47+
*/
4248
public Map<String, InterpreterProperty> getProperties() {
49+
properties.forEach((key, property) -> {
50+
if (isNumberType(property) && isWholeNumberDouble(property.getValue())) {
51+
convertDoubleToInt(property);
52+
}
53+
});
4354
return properties;
4455
}
4556

57+
/**
58+
* Checks if the property type is "number".
59+
*
60+
* @param property The InterpreterProperty to check.
61+
* @return true if the property type is "number", false otherwise.
62+
*/
63+
private boolean isNumberType(InterpreterProperty property) {
64+
return "number".equals(property.getType());
65+
}
66+
67+
/**
68+
* Checks if the given value is a Double and represents a whole number.
69+
*
70+
* @param value The object to check.
71+
* @return true if the value is a Double and a whole number, false otherwise.
72+
*/
73+
private boolean isWholeNumberDouble(Object value) {
74+
if (value instanceof Double) {
75+
Double doubleValue = (Double) value;
76+
return doubleValue == Math.floor(doubleValue);
77+
}
78+
return false;
79+
}
80+
81+
/**
82+
* Converts the value of the given property from a Double to an Integer if the Double represents a whole number.
83+
*
84+
* @param property The InterpreterProperty whose value will be converted.
85+
*/
86+
private void convertDoubleToInt(InterpreterProperty property) {
87+
Double doubleValue = (Double) property.getValue();
88+
property.setValue(doubleValue.intValue());
89+
}
90+
4691
public List<Dependency> getDependencies() {
4792
return dependencies;
4893
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.zeppelin.rest.message;
18+
19+
import org.apache.zeppelin.dep.Dependency;
20+
import org.apache.zeppelin.interpreter.InterpreterOption;
21+
import org.apache.zeppelin.interpreter.InterpreterProperty;
22+
import org.junit.jupiter.api.BeforeEach;
23+
import org.junit.jupiter.api.Test;
24+
25+
import java.util.Collections;
26+
import java.util.HashMap;
27+
import java.util.List;
28+
import java.util.Map;
29+
30+
import static org.junit.jupiter.api.Assertions.*;
31+
import static org.mockito.Mockito.*;
32+
33+
/**
34+
* Unit test class for the UpdateInterpreterSettingRequest.
35+
* This class tests the behavior of UpdateInterpreterSettingRequest methods,
36+
* especially focusing on property type handling and value conversions.
37+
*/
38+
class UpdateInterpreterSettingRequestTest {
39+
40+
private Map<String, InterpreterProperty> properties;
41+
private List<Dependency> dependencies;
42+
private InterpreterOption option;
43+
private UpdateInterpreterSettingRequest request;
44+
45+
/**
46+
* Setup method that initializes test fixtures before each test.
47+
* Mocks dependencies and option objects to isolate UpdateInterpreterSettingRequest behavior.
48+
*/
49+
@BeforeEach
50+
void setUp() {
51+
properties = new HashMap<>();
52+
dependencies = Collections.emptyList();
53+
option = mock(InterpreterOption.class);
54+
request = new UpdateInterpreterSettingRequest(properties, dependencies, option);
55+
}
56+
57+
/**
58+
* Tests getProperties method to verify that properties with "number" type
59+
* and whole-number Double values are correctly converted to Integer.
60+
* Verifies that only whole-number Doubles are converted and non-integer Doubles remain unchanged.
61+
*/
62+
@Test
63+
void testGetPropertiesWithWholeNumberDoubleConversion() {
64+
InterpreterProperty property1 = mock(InterpreterProperty.class);
65+
when(property1.getType()).thenReturn("number");
66+
when(property1.getValue()).thenReturn(5.0);
67+
68+
InterpreterProperty property2 = mock(InterpreterProperty.class);
69+
when(property2.getType()).thenReturn("number");
70+
when(property2.getValue()).thenReturn(5.5);
71+
72+
properties.put("property1", property1);
73+
properties.put("property2", property2);
74+
75+
Map<String, InterpreterProperty> resultProperties = request.getProperties();
76+
77+
verify(property1).setValue(5);
78+
verify(property2, never()).setValue(any());
79+
assertEquals(properties, resultProperties);
80+
}
81+
82+
/**
83+
* Tests getProperties method when the property type is not "number".
84+
* Verifies that no conversion is performed on non-number types.
85+
*/
86+
@Test
87+
void testGetPropertiesWithoutConversion() {
88+
InterpreterProperty property = mock(InterpreterProperty.class);
89+
when(property.getType()).thenReturn("string");
90+
when(property.getValue()).thenReturn("test");
91+
92+
properties.put("property", property);
93+
94+
Map<String, InterpreterProperty> resultProperties = request.getProperties();
95+
96+
verify(property, never()).setValue(any());
97+
assertEquals(properties, resultProperties);
98+
}
99+
100+
/**
101+
* Tests getDependencies method to confirm that it returns the correct dependencies list.
102+
*/
103+
@Test
104+
void testGetDependencies() {
105+
assertEquals(dependencies, request.getDependencies());
106+
}
107+
108+
/**
109+
* Tests getOption method to confirm that it returns the correct interpreter option.
110+
*/
111+
@Test
112+
void testGetOption() {
113+
assertEquals(option, request.getOption());
114+
}
115+
}

0 commit comments

Comments
 (0)