e8261465创建于 2024年12月10日历史提交
/*
 * Copyright (c) 2024 Huawei Technologies Co.,Ltd.
 *
 * openGauss is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * --------------------------------------------------------------------------------------
 *
 * gms_match.cpp
 *  gms_match can match two records.
 *
 *
 * IDENTIFICATION
 *        contrib/gms_match/gms_match.cpp
 * 
 * --------------------------------------------------------------------------------------
 */
#include "utils/builtins.h"
#include "gms_match.h"

PG_MODULE_MAGIC;

PG_FUNCTION_INFO_V1(edit_distance);
PG_FUNCTION_INFO_V1(edit_distance_similarity);

static int min_edit_distance(char* s1, char* s2);

Datum edit_distance(PG_FUNCTION_ARGS) {
    if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) {
        PG_RETURN_INT32(-1);
    }
    char *str1 = text_to_cstring(PG_GETARG_TEXT_P(0));
    char *str2 = text_to_cstring(PG_GETARG_TEXT_P(1));
    int result = min_edit_distance(str1, str2);
    pfree_ext(str1);
    pfree_ext(str2);
    PG_RETURN_INT32(result);
}

Datum edit_distance_similarity(PG_FUNCTION_ARGS) {
    if (PG_ARGISNULL(0) && PG_ARGISNULL(1)) {
        PG_RETURN_INT32(100);
    }

    if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) {
        PG_RETURN_INT32(0);
    }

    char *str1 = text_to_cstring(PG_GETARG_TEXT_P(0));
    char *str2 = text_to_cstring(PG_GETARG_TEXT_P(1));
    int edit_distance = min_edit_distance(str1, str2);
    int max_len = strlen(str1) > strlen(str2) ? strlen(str1) : strlen(str2);
    int similarly = 100 - edit_distance * 100 / max_len;
    pfree_ext(str1);
    pfree_ext(str2);
    PG_RETURN_INT32(similarly);
}

static int min_edit_distance(char* s1, char* s2) {
    if (strcmp(s1, s2) == 0) {
        return 0;
    }

    int len_s1 = strlen(s1);
    int len_s2 = strlen(s2);

    int dp_array[len_s1 + 1][len_s2 + 1];
    for (int i = 0; i <= len_s1; i++) {
        for (int j = 0; j <= len_s2; j++) {
            if (i == 0) {
                dp_array[i][j] = j;
            } else if (j == 0) {
                dp_array[i][j] = i;
            } else {
                int cost = (s1[i - 1] == s2[j - 1]) ? 0 : 1;
                dp_array[i][j] = Min(Min(dp_array[i - 1][j] + 1, dp_array[i][j - 1] + 1), dp_array[i - 1][j - 1] + cost);
            }
        }
    }
    return dp_array[len_s1][len_s2];
}