All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.hudi.metadata.SecondaryIndexKeyUtils Maven / Gradle / Ivy

The newest version!
/*
 * 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.hudi.metadata;

import static org.apache.hudi.common.util.ValidationUtils.checkState;
import static org.apache.hudi.metadata.HoodieMetadataPayload.SECONDARY_INDEX_RECORD_KEY_SEPARATOR;

public class SecondaryIndexKeyUtils {

  public static String getRecordKeyFromSecondaryIndexKey(String key) {
    // the payload key is in the format of "secondaryKey$primaryKey"
    // we need to extract the primary key from the payload key
    checkState(key.contains(SECONDARY_INDEX_RECORD_KEY_SEPARATOR), "Invalid key format for secondary index payload: " + key);
    int delimiterIndex = getSecondaryIndexKeySeparatorPosition(key);
    return unescapeSpecialChars(key.substring(delimiterIndex + 1));
  }

  public static String getSecondaryKeyFromSecondaryIndexKey(String key) {
    // the payload key is in the format of "secondaryKey$primaryKey"
    // we need to extract the secondary key from the payload key
    checkState(key.contains(SECONDARY_INDEX_RECORD_KEY_SEPARATOR), "Invalid key format for secondary index payload: " + key);
    int delimiterIndex = getSecondaryIndexKeySeparatorPosition(key);
    return unescapeSpecialChars(key.substring(0, delimiterIndex));
  }

  static String constructSecondaryIndexKey(String secondaryKey, String recordKey) {
    return escapeSpecialChars(secondaryKey) + SECONDARY_INDEX_RECORD_KEY_SEPARATOR + escapeSpecialChars(recordKey);
  }

  private static String escapeSpecialChars(String str) {
    StringBuilder escaped = new StringBuilder();
    for (char c : str.toCharArray()) {
      if (c == '\\' || c == '$') {
        escaped.append('\\');  // Add escape character
      }
      escaped.append(c);  // Add the actual character
    }
    return escaped.toString();
  }

  private static int getSecondaryIndexKeySeparatorPosition(String key) {
    int delimiterIndex = -1;
    boolean isEscape = false;

    // Find the delimiter index while skipping escaped $
    for (int i = 0; i < key.length(); i++) {
      char c = key.charAt(i);
      if (c == '\\' && !isEscape) {
        isEscape = true;
      } else if (c == '$' && !isEscape) {
        delimiterIndex = i;
        break;
      } else {
        isEscape = false;
      }
    }
    checkState(delimiterIndex != -1, "Invalid encoded key format");
    return delimiterIndex;
  }

  private static String unescapeSpecialChars(String str) {
    StringBuilder unescaped = new StringBuilder();
    boolean isEscape = false;
    for (char c : str.toCharArray()) {
      if (isEscape) {
        unescaped.append(c);
        isEscape = false;
      } else if (c == '\\') {
        isEscape = true;  // Set escape flag to skip next character
      } else {
        unescaped.append(c);
      }
    }
    return unescaped.toString();
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy