This is an automated email from the ASF dual-hosted git repository.

siddteotia pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new b3263337a8 Support JSON column type in recommender. (#8965)
b3263337a8 is described below

commit b3263337a8763d3d3415790270d7b2dbf8cc3194
Author: Amrish Lal <[email protected]>
AuthorDate: Tue Jun 28 19:55:55 2022 -0700

    Support JSON column type in recommender. (#8965)
    
    * Support JSON column type in recommender.
    
    * Fix code format.
    
    * codereview changes.
    
    * Add JSON to TestConfigEngine test case.
    
    * Code format.
    
    * Rebuild.
    
    * codereview changes + cleanup.
    
    * Rebuild.
    
    * Rule for recommending NoDictionary and JsonIndex on JSON columns.
    
    * Add licence header.
---
 .../data/generator/GeneratorFactory.java           |  3 +
 .../recommender/data/generator/JsonGenerator.java  | 62 ++++++++++++++++++++
 .../controller/recommender/io/InputManager.java    |  3 +
 .../realtime/provisioning/MemoryEstimator.java     |  6 ++
 .../recommender/rules/RulesToExecute.java          | 14 +++++
 .../recommender/rules/impl/JsonIndexRule.java      | 55 +++++++++++++++++
 .../recommender/rules/io/configs/IndexConfig.java  | 14 +++++
 .../rules/io/params/RecommenderConstants.java      |  1 +
 .../controller/recommender/TestConfigEngine.java   | 16 ++++-
 .../data/generator/JsonGeneratorTest.java          | 68 ++++++++++++++++++++++
 .../recommenderInput/SegmentSizeRuleInput.json     | 11 +++-
 11 files changed, 250 insertions(+), 3 deletions(-)

diff --git 
a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/data/generator/GeneratorFactory.java
 
b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/data/generator/GeneratorFactory.java
index 3496935fb4..4186543eec 100644
--- 
a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/data/generator/GeneratorFactory.java
+++ 
b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/data/generator/GeneratorFactory.java
@@ -36,6 +36,9 @@ public class GeneratorFactory {
     if (type == DataType.STRING) {
       return new StringGenerator(cardinality, numberOfValuesPerEntry, 
entryLength);
     }
+    if (type == DataType.JSON) {
+      return new JsonGenerator(entryLength);
+    }
     if (type == DataType.BYTES) {
       return new BytesGenerator(cardinality, entryLength);
     }
diff --git 
a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/data/generator/JsonGenerator.java
 
b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/data/generator/JsonGenerator.java
new file mode 100644
index 0000000000..cb7d4ec0c5
--- /dev/null
+++ 
b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/data/generator/JsonGenerator.java
@@ -0,0 +1,62 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pinot.controller.recommender.data.generator;
+
+import java.util.Random;
+
+
+public class JsonGenerator implements Generator {
+  // Length of each key-value pair int the JSON string.
+  static final int DEFAULT_JSON_ELEMENT_LENGTH = 5;
+
+  private final int _jsonStringLength;
+  private final Random _random;
+
+  public JsonGenerator(Integer jsonSize) {
+    _jsonStringLength = jsonSize == null || jsonSize <= 0 ? 0 : jsonSize;
+    _random = new Random(System.currentTimeMillis());
+  }
+
+  @Override
+  public void init() {
+  }
+
+  @Override
+  public Object next() {
+    // Return empty string if size of json string is zero or if number of 
elements is zero.
+    if (_jsonStringLength == 0 || _jsonStringLength / 
DEFAULT_JSON_ELEMENT_LENGTH == 0) {
+      return "{}";
+    }
+
+    // Create JSON string { "<character>":<integer>, "<character>":<integer>, 
...} as per length specified. Escape
+    // comma's in JSON since comma is used as delimiter in CSV data file that 
will be used to generate segment.
+    StringBuffer jsonBuffer = new StringBuffer();
+    int elementCount = _jsonStringLength / DEFAULT_JSON_ELEMENT_LENGTH;
+    jsonBuffer.append("{");
+    for (int i = 0; i < elementCount; i++) {
+      if (jsonBuffer.length() > 1) {
+        jsonBuffer.append("\\,");
+      }
+      String item = "\"" + (char) ('a' + _random.nextInt(26)) + "\":" + 
_random.nextInt(10);
+      jsonBuffer.append(item);
+    }
+
+    return jsonBuffer.append("}").toString();
+  }
+}
diff --git 
a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/io/InputManager.java
 
b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/io/InputManager.java
index fb74b85a48..02aca45911 100644
--- 
a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/io/InputManager.java
+++ 
b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/io/InputManager.java
@@ -135,6 +135,7 @@ public class InputManager {
     put(FieldSpec.DataType.DOUBLE, Double.BYTES);
     put(FieldSpec.DataType.BYTES, Byte.BYTES);
     put(FieldSpec.DataType.STRING, Character.BYTES);
+    put(FieldSpec.DataType.JSON, Character.BYTES);
     put(FieldSpec.DataType.BOOLEAN, Integer.BYTES); // Stored internally as an 
INTEGER
     put(null, DEFAULT_NULL_SIZE);
   }};
@@ -220,6 +221,7 @@ public class InputManager {
     String sortedColumn = 
_overWrittenConfigs.getIndexConfig().getSortedColumn();
     Set<String> invertedIndexColumns = 
_overWrittenConfigs.getIndexConfig().getInvertedIndexColumns();
     Set<String> rangeIndexColumns = 
_overWrittenConfigs.getIndexConfig().getRangeIndexColumns();
+    Set<String> jsonIndexColumns = 
_overWrittenConfigs.getIndexConfig().getJsonIndexColumns();
     Set<String> noDictionaryColumns = 
_overWrittenConfigs.getIndexConfig().getNoDictionaryColumns();
 
     /*Validate if there's conflict between NoDictionaryColumns and 
dimNamesWithAnyIndex*/
@@ -227,6 +229,7 @@ public class InputManager {
     dimNamesWithAnyIndex.add(sortedColumn);
     dimNamesWithAnyIndex.addAll(invertedIndexColumns);
     dimNamesWithAnyIndex.addAll(rangeIndexColumns);
+    dimNamesWithAnyIndex.addAll(jsonIndexColumns);
     for (String colName : noDictionaryColumns) {
       if (dimNamesWithAnyIndex.contains(colName)) {
         throw new InvalidInputException(
diff --git 
a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/realtime/provisioning/MemoryEstimator.java
 
b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/realtime/provisioning/MemoryEstimator.java
index fd915e1609..baa2ea4b52 100644
--- 
a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/realtime/provisioning/MemoryEstimator.java
+++ 
b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/realtime/provisioning/MemoryEstimator.java
@@ -40,6 +40,7 @@ import 
org.apache.pinot.controller.recommender.io.metadata.FieldMetadata;
 import org.apache.pinot.controller.recommender.io.metadata.SchemaWithMetaData;
 import 
org.apache.pinot.controller.recommender.io.metadata.TimeFieldSpecMetadata;
 import 
org.apache.pinot.controller.recommender.io.metadata.TimeGranularitySpecMetadata;
+import org.apache.pinot.plugin.inputformat.csv.CSVRecordReaderConfig;
 import 
org.apache.pinot.segment.local.indexsegment.immutable.ImmutableSegmentLoader;
 import org.apache.pinot.segment.local.indexsegment.mutable.MutableSegmentImpl;
 import 
org.apache.pinot.segment.local.io.readerwriter.RealtimeIndexOffHeapMemoryManager;
@@ -583,6 +584,11 @@ public class MemoryEstimator {
       segmentGeneratorConfig.setOutDir(outDir);
       segmentGeneratorConfig.setTableName(_tableConfig.getTableName());
       segmentGeneratorConfig.setSequenceId(0);
+
+      CSVRecordReaderConfig recordReaderConfig = new CSVRecordReaderConfig();
+      recordReaderConfig.setEscapeCharacter('\\');
+      segmentGeneratorConfig.setReaderConfig(recordReaderConfig);
+
       return segmentGeneratorConfig;
     }
   }
diff --git 
a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/RulesToExecute.java
 
b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/RulesToExecute.java
index 01d744461f..54e9e17ede 100644
--- 
a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/RulesToExecute.java
+++ 
b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/RulesToExecute.java
@@ -26,6 +26,7 @@ import 
org.apache.pinot.controller.recommender.rules.impl.AggregateMetricsRule;
 import org.apache.pinot.controller.recommender.rules.impl.BloomFilterRule;
 import org.apache.pinot.controller.recommender.rules.impl.FlagQueryRule;
 import 
org.apache.pinot.controller.recommender.rules.impl.InvertedSortedIndexJointRule;
+import org.apache.pinot.controller.recommender.rules.impl.JsonIndexRule;
 import org.apache.pinot.controller.recommender.rules.impl.KafkaPartitionRule;
 import 
org.apache.pinot.controller.recommender.rules.impl.NoDictionaryOnHeapDictionaryJointRule;
 import 
org.apache.pinot.controller.recommender.rules.impl.PinotTablePartitionRule;
@@ -61,6 +62,8 @@ public class RulesToExecute {
           return new BloomFilterRule(inputManager, outputManager);
         case RangeIndexRule:
           return new RangeIndexRule(inputManager, outputManager);
+        case JsonIndexRule:
+          return new JsonIndexRule(inputManager, outputManager);
         case NoDictionaryOnHeapDictionaryJointRule:
           return new NoDictionaryOnHeapDictionaryJointRule(inputManager, 
outputManager);
         case VariedLengthDictionaryRule:
@@ -82,6 +85,7 @@ public class RulesToExecute {
   boolean _recommendInvertedSortedIndexJoint = 
DEFAULT_RECOMMEND_INVERTED_SORTED_INDEX_JOINT;
   boolean _recommendBloomFilter = DEFAULT_RECOMMEND_BLOOM_FILTER;
   boolean _recommendRangeIndex = DEFAULT_RECOMMEND_RANGE_INDEX;
+  boolean _recommendJsonIndex = DEFAULT_RECOMMEND_JSON_INDEX;
   boolean _recommendNoDictionaryOnHeapDictionaryJoint = 
DEFAULT_RECOMMEND_NO_DICTIONARY_ONHEAP_DICTIONARY_JOINT;
   boolean _recommendVariedLengthDictionary = 
DEFAULT_RECOMMEND_VARIED_LENGTH_DICTIONARY;
   boolean _recommendFlagQuery = DEFAULT_RECOMMEND_FLAG_QUERY;
@@ -128,6 +132,11 @@ public class RulesToExecute {
     _recommendRangeIndex = recommendRangeIndex;
   }
 
+  @JsonSetter(nulls = Nulls.SKIP)
+  public void setRecommendJsonIndex(boolean recommendJsonIndex) {
+    _recommendJsonIndex = recommendJsonIndex;
+  }
+
   @JsonSetter(nulls = Nulls.SKIP)
   public void setRecommendAggregateMetrics(boolean aggregateMetrics) {
     _recommendAggregateMetrics = aggregateMetrics;
@@ -175,6 +184,10 @@ public class RulesToExecute {
     return _recommendRangeIndex;
   }
 
+  public boolean isRecommendJsonIndex() {
+    return _recommendJsonIndex;
+  }
+
   public boolean isRecommendAggregateMetrics() {
     return _recommendAggregateMetrics;
   }
@@ -203,6 +216,7 @@ public class RulesToExecute {
     // partitions, after NoDictionaryOnHeapDictionaryJointRule to correctly 
calculate record size
     BloomFilterRule,
     RangeIndexRule,
+    JsonIndexRule,
     AggregateMetricsRule,
     RealtimeProvisioningRule // this rule must be the last one because it 
needs the output of other rules as its input
   }
diff --git 
a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/JsonIndexRule.java
 
b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/JsonIndexRule.java
new file mode 100644
index 0000000000..df36f742d7
--- /dev/null
+++ 
b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/JsonIndexRule.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pinot.controller.recommender.rules.impl;
+
+import 
org.apache.pinot.controller.recommender.exceptions.InvalidInputException;
+import org.apache.pinot.controller.recommender.io.ConfigManager;
+import org.apache.pinot.controller.recommender.io.InputManager;
+import org.apache.pinot.controller.recommender.rules.AbstractRule;
+import org.apache.pinot.controller.recommender.rules.io.configs.IndexConfig;
+import org.apache.pinot.spi.data.FieldSpec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/** JSON columns must be NoDictionary columns with JsonIndex. */
+public class JsonIndexRule extends AbstractRule {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(RangeIndexRule.class);
+
+  public JsonIndexRule(InputManager input, ConfigManager output) {
+    super(input, output);
+  }
+
+  @Override
+  public void run()
+      throws InvalidInputException {
+    int numColumns = _input.getNumCols();
+    IndexConfig indexConfig = _output.getIndexConfig();
+    for (int i = 0; i < numColumns; i++) {
+      String columnName = _input.intToColName(i);
+      FieldSpec.DataType columnType = _input.getFieldType(columnName);
+      if (columnType == FieldSpec.DataType.JSON) {
+        // JSON columns must be NoDictionary columns and have a JsonIndex.
+        LOGGER.info("Recommending NoDictionary and JsonIndex on JSON column 
{}.", columnName);
+        indexConfig.getJsonIndexColumns().add(columnName);
+        indexConfig.getNoDictionaryColumns().add(columnName);
+      }
+    }
+  }
+}
diff --git 
a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/io/configs/IndexConfig.java
 
b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/io/configs/IndexConfig.java
index 160491a6b5..d54d84424c 100644
--- 
a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/io/configs/IndexConfig.java
+++ 
b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/io/configs/IndexConfig.java
@@ -33,6 +33,7 @@ public class IndexConfig {
   Set<String> _rangeIndexColumns = new HashSet<>();
   String _sortedColumn = "";
   Set<String> _bloomFilterColumns = new HashSet<>();
+  Set<String> _jsonIndexColumns = new HashSet<>();
 
   Set<String> _noDictionaryColumns = new HashSet<>();
   Set<String> _onHeapDictionaryColumns = new HashSet<>();
@@ -84,6 +85,11 @@ public class IndexConfig {
     _isSortedColumnOverwritten = sortedColumnOverwritten;
   }
 
+  @JsonSetter(nulls = Nulls.SKIP)
+  public void setJsonIndexColumns(Set<String> jsonIndexColumns) {
+    _jsonIndexColumns = jsonIndexColumns;
+  }
+
   public Set<String> getVarLengthDictionaryColumns() {
     return _varLengthDictionaryColumns;
   }
@@ -112,6 +118,10 @@ public class IndexConfig {
     return _rangeIndexColumns;
   }
 
+  public Set<String> getJsonIndexColumns() {
+    return _jsonIndexColumns;
+  }
+
   public boolean hasInvertedIndex(String colname) {
     return _invertedIndexColumns.contains(colname);
   }
@@ -124,6 +134,10 @@ public class IndexConfig {
     return _rangeIndexColumns.contains(colName);
   }
 
+  public boolean hasJsonIndex(String colName) {
+    return _jsonIndexColumns.contains(colName);
+  }
+
   public boolean hasAnyIndex() {
     return !_sortedColumn.isEmpty() || !_rangeIndexColumns.isEmpty() || 
!_invertedIndexColumns.isEmpty();
   }
diff --git 
a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/io/params/RecommenderConstants.java
 
b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/io/params/RecommenderConstants.java
index 2cda521399..1a707fb4f4 100644
--- 
a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/io/params/RecommenderConstants.java
+++ 
b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/io/params/RecommenderConstants.java
@@ -48,6 +48,7 @@ public class RecommenderConstants {
     public static final boolean DEFAULT_RECOMMEND_INVERTED_SORTED_INDEX_JOINT 
= true;
     public static final boolean DEFAULT_RECOMMEND_BLOOM_FILTER = true;
     public static final boolean DEFAULT_RECOMMEND_RANGE_INDEX = true;
+    public static final boolean DEFAULT_RECOMMEND_JSON_INDEX = true;
     public static final boolean 
DEFAULT_RECOMMEND_NO_DICTIONARY_ONHEAP_DICTIONARY_JOINT = true;
     public static final boolean DEFAULT_RECOMMEND_AGGREGATE_METRICS = true;
     public static final boolean DEFAULT_RECOMMEND_REALTIME_PROVISIONING = true;
diff --git 
a/pinot-controller/src/test/java/org/apache/pinot/controller/recommender/TestConfigEngine.java
 
b/pinot-controller/src/test/java/org/apache/pinot/controller/recommender/TestConfigEngine.java
index 26d33570b0..58362560d6 100644
--- 
a/pinot-controller/src/test/java/org/apache/pinot/controller/recommender/TestConfigEngine.java
+++ 
b/pinot-controller/src/test/java/org/apache/pinot/controller/recommender/TestConfigEngine.java
@@ -281,6 +281,18 @@ public class TestConfigEngine {
     assertEquals(output.getIndexConfig().getRangeIndexColumns().toString(), 
"[t, j]");
   }
 
+  /** Verifiy rule that recommends JsonIndex and NoDictionary on JSON columns. 
*/
+  @Test
+  void testJsonIndexRule()
+      throws InvalidInputException, IOException {
+    loadInput("recommenderInput/SegmentSizeRuleInput.json");
+    ConfigManager output = new ConfigManager();
+    AbstractRule abstractRule = 
RulesToExecute.RuleFactory.getRule(RulesToExecute.Rule.JsonIndexRule, _input, 
output);
+    abstractRule.run();
+    assertEquals(output.getIndexConfig().getJsonIndexColumns().toString(), 
"[q]");
+    assertEquals(output.getIndexConfig().getNoDictionaryColumns().toString(), 
"[q]");
+  }
+
   @Test
   void testNoDictionaryOnHeapDictionaryJointRule()
       throws InvalidInputException, IOException {
@@ -464,8 +476,8 @@ public class TestConfigEngine {
       throws Exception {
     ConfigManager output = 
runRecommenderDriver("recommenderInput/SegmentSizeRuleInput.json");
     SegmentSizeRecommendations segmentSizeRecommendations = 
output.getSegmentSizeRecommendations();
-    assertEquals(segmentSizeRecommendations.getNumSegments(), 2);
-    assertEquals(segmentSizeRecommendations.getNumRowsPerSegment(), 50_000);
+    assertEquals(segmentSizeRecommendations.getNumSegments(), 3);
+    assertEquals(segmentSizeRecommendations.getNumRowsPerSegment(), 33_333);
   }
 
   @Test
diff --git 
a/pinot-controller/src/test/java/org/apache/pinot/controller/recommender/data/generator/JsonGeneratorTest.java
 
b/pinot-controller/src/test/java/org/apache/pinot/controller/recommender/data/generator/JsonGeneratorTest.java
new file mode 100644
index 0000000000..c4bcc1ccc3
--- /dev/null
+++ 
b/pinot-controller/src/test/java/org/apache/pinot/controller/recommender/data/generator/JsonGeneratorTest.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pinot.controller.recommender.data.generator;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import java.io.IOException;
+import org.apache.commons.lang.StringUtils;
+import org.apache.pinot.spi.utils.JsonUtils;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+
+public class JsonGeneratorTest {
+
+  @Test
+  public void testNext()
+      throws IOException {
+    // JsonGenerator generates empty json when size is less than 
JsonGenerator.DEFAULT_JSON_ELEMENT_LENGTH
+    JsonGenerator jsonGenerator1 = new JsonGenerator(0);
+    Assert.assertEquals(jsonGenerator1.next(), "{}");
+
+    JsonGenerator jsonGenerator2 = new JsonGenerator(4);
+    Assert.assertEquals(jsonGenerator2.next(), "{}");
+
+    JsonGenerator jsonGenerator3 = new JsonGenerator(8);
+    checkJson((String) jsonGenerator3.next(), 8);
+
+    JsonGenerator jsonGenerator4 = new JsonGenerator(20);
+    checkJson((String) jsonGenerator4.next(), 20);
+  }
+
+  public static void checkJson(String jsonString, int desiredLength)
+      throws IOException {
+
+    // Number of expected elements in the generated JSON string
+    int elementCount = desiredLength / 
JsonGenerator.DEFAULT_JSON_ELEMENT_LENGTH;
+
+    // Remove escape characters from jsonString for verification purposes. 
Escape character were added before comma
+    // since json string is written to a CSV file where comma is used as 
delimiter.
+    jsonString = StringUtils.remove(jsonString, "\\");
+
+    // Make sure we are generating JSON string that is close to the desired 
length. Length of JSON string should be 2
+    // (length of opening and closing parentheses) + number of commas + size 
of all the elements.
+    Assert.assertEquals(jsonString.length(),
+        "{}".length() + (elementCount - 1) + elementCount * 
JsonGenerator.DEFAULT_JSON_ELEMENT_LENGTH);
+
+    // Check if json string is valid json (i.e does not throw parse 
exceptions) and doesn't result in a
+    // JsonNode "missing node".
+    JsonNode jsonNode = JsonUtils.stringToJsonNode(jsonString);
+    Assert.assertFalse(jsonNode.isMissingNode());
+  }
+}
diff --git 
a/pinot-controller/src/test/resources/recommenderInput/SegmentSizeRuleInput.json
 
b/pinot-controller/src/test/resources/recommenderInput/SegmentSizeRuleInput.json
index fc1170f1ca..4c11943acd 100644
--- 
a/pinot-controller/src/test/resources/recommenderInput/SegmentSizeRuleInput.json
+++ 
b/pinot-controller/src/test/resources/recommenderInput/SegmentSizeRuleInput.json
@@ -72,6 +72,14 @@
         "cardinality":4,
         "numValuesPerEntry":1.00000001,
         "singleValueField": false
+      },
+      {
+        "name": "q",
+        "dataType": "JSON",
+        "cardinality":4,
+        "numValuesPerEntry":1,
+        "averageLength" : 25,
+        "singleValueField": true
       }
     ],
     "metricFieldSpecs": [
@@ -131,7 +139,8 @@
     "select j from tableName where (a=3 and (h = 5 or f >34) and 
REGEXP_LIKE(i, 'as*')) or ((f = 3  or j in ('#VALUES', 4)) and REGEXP_LIKE(d, 
'fl*'))": 2,
     "select f from tableName where (a=0 or (b=1 and (e in ('#VALUES',2) or 
c=7))) and TEXT_MATCH(d, 'dasd') and MAX(MAX(h,i),j)=4 and t<3": 4,
     "select f from tableName where (a=0 and b=1) or c=7 or (d = 7 and e =1)": 
2,
-    "select f from tableName where t between 1 and 1000": 2
+    "select f from tableName where t between 1 and 1000": 2,
+    "select q from tableName where JSON_MATCH(q, '\"$.a\" IS NOT NULL')": 1
   },
   "qps": 400,
   "numMessagesPerSecInKafkaTopic":1000,


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to