카테고리 없음

16일차 / axios 요청 작성, fuzzy검색 및 정렬, 리벤슈타인 거리

fullfish 2022. 5. 12. 02:37

한것

axios 요청 작성

서버에서 퍼지검색을하고 프론트에서 정렬을 했었는데 검색과 정렬모두 서버에서로 변경

리벤슈타인거리 추가 (퍼지검색 -> 퍼지검색한거 유사도 정렬 -> 리벤슈타인 거리 적합한것 추가)

리벤슈타인거리에 해당하는것은 로직이 달라서 하이라이트 별개로줌

 

axios 요청 예시

export function diaryGet(trip_id, search) {
  let url = `${endpoint}/diary?trip_id=${trip_id}`;
  if (search) url += `&search=${search}`;
  return axios.get(url, {
    headers: tokenHeader(),
    'Content-Type': 'application/json',
  });
}
export default function tokenHeader() {
  const user = JSON.parse(localStorage.getItem('user'));
  if (user && user.accessToken) {
    return { Authorization: 'Bearer ' + user.accessToken };
  } else {
    return {};
  }
}

get쪽 코드

   const data = await diary.findAll({
          where: {
            trip_id,
          },
        });
        const hashtagsInfo = await diary.findAll({
          include: [
            {
              model: hashtag,
              attributes: ["hashtag"], //select 뒤에 오는거 뭐 찾을지 없으면 all
            },
          ],
          where: {
            trip_id,
          },
        });
        hashtagsInfo.forEach((ele, index) => {
          let hashtags = [];
          ele.hashtags.forEach((ele) => {
            hashtags.push(ele.hashtag);
          });
          data[index].dataValues.hashtags = hashtags;
        });
        const fuzzyData = data.filter((ele) => {
          return fuzzy.createFuzzyMatcher(search).test(ele.dataValues.title);
        });
        const levenshteinData = data.filter((ele) => {
          return levenshteinDistance.levenshteinDistance(ele.dataValues.title, search) <= 1;
        });
        fuzzy.sort(fuzzyData, search);

        let resultData = fuzzyData.slice();

        for (let i = 0; i < levenshteinData.length; i++) {
          if (
            !resultData.map((ele) => ele.dataValues.id).includes(levenshteinData[i].dataValues.id)
          ) {
            resultData.push(levenshteinData[i]);
          }
        }

레벤슈타인거리 : https://fullfish.tistory.com/106

 

레벤슈타인 거리 (Levenshtein Distance)

레벤슈타인 거리란 문자열의 유사도를 검사하는 기본적인 알고리즘으로 편집 거리라고도 부름 a문자열에서 b문자열로 편집할때 몇번의 조작이 필요한지를 도출해낸다 예를들어 '가나다라'와 '

fullfish.tistory.com

해당 tirp_id에 대한 데이터를 data로 다 받아옴

diary.findAll할때 includ로 hashtag을 주면 hashtag까지 받아와지지만

hashtags를 참조하려면 data[].hashtags[].dataValuses.hashtag로 복잡하며 hashtags[]부분에서 배열로 나뉘어서

hashtagsInfo를 따로 받아와서 forEach문으로 data에 키를 만들어서 hashtags를 추가해줬다

 

그리고 fuzzy검색으로 검색되는것만을 filter해서 fuzzyData에 넣고

레벤슈타인거리 1이하인것을 filter해서 levenshteinData에 넣고

fuzzyData를 적합도 높은것을 위쪽으로 정렬합니다
("과자"로 검색시 "과일먹자"보다 "새우깡은과자다"가 더 유사도가 높지만 db저장 순서가 "과일먹자"가 더 빠르면 "과일먹자"가 상위에 검색되므로 아래로 정렬함)

그리고 정렬한 fuzzyData에 levenshteinData를 push해준다 

이것은 따로 정렬할 필요가 없는것이

글자 한개가 틀린것자체가 이미 퍼지검색보다 유사도가 낮다

 

하이라이트 부분 코드

exports.chageRed = (data, search) => {
  // 정규식 이용한 fuzzy검색결과 색 바꿈
  const regex = createFuzzyMatcher(search);
  const resultData = data.replace(regex, (match, ...groups) => {
    const letters = groups.slice(0, search.length);
    let lastIndex = 0;
    let redColor = [];
    for (let i = 0, l = letters.length; i < l; i++) {
      const idx = match.indexOf(letters[i], lastIndex);
      redColor.push(match.substring(lastIndex, idx));
      redColor.push(`<span style="color: red">${letters[i]}</span>`);
      lastIndex = idx + 1;
    }
    return redColor.join('');
  });
  if (resultData !== data) return resultData;
  // 리벤슈타인거리 이용한 검색 결과 색 바꿈
  else {
    let redColor = [];
    let index = 0;
    if (search === undefined) return;
    for (let i = 0; i < data.length; i++) {
      if (search.indexOf(data[i], index) === -1) {
        redColor.push(data[i]);
        // data = data.slice(i);
      } else {
        redColor.push(`<span style="color: red">${data[i]}</span>`);
        index++;
      }
    }
    return redColor.join('');
  }
};

퍼지검색과 리벤슈타인거리 검색은 로직이 달라서

하이라이트 주는 부분을 따로 주었다

 

 

--이후 수정된 하이라이트 코드 (글자 순서 달라도 검색이 되게끔 하면서 보완함)

exports.chageRed = (data, search) => {
  // 완벽일치시 그것 먼저 색 바꿈
  if (data.indexOf(search) !== -1) {
    let redColor = [];
    let count = 0;
    for (let i = 0; i < data.length; i++) {
      if (i >= data.indexOf(search) && count !== search.length) {
        redColor.push(`<span style="color: red">${data[i]}</span>`);
        count++;
      } else redColor.push(data[i]);
    }
    return redColor.join('');
  }
  // 정규식 이용한 fuzzy검색결과 색 바꿈
  const regex = createFuzzyMatcher(search);
  const resultData = data.replace(regex, (match, ...groups) => {
    const letters = groups.slice(0, search.length);
    let lastIndex = 0;
    let redColor = [];
    for (let i = 0, l = letters.length; i < l; i++) {
      const idx = match.indexOf(letters[i], lastIndex);
      redColor.push(match.substring(lastIndex, idx));
      redColor.push(`<span style="color: red">${letters[i]}</span>`);
      lastIndex = idx + 1;
    }
    return redColor.join('');
  });
  if (resultData !== data) return resultData;
  // 리벤슈타인거리 이용한 검색 결과 색 바꿈
  else {
    let redColor = [];
    if (search === undefined) return;
    for (let i = 0; i < data.length; i++) {
      if (search.indexOf(data[i]) === -1) {
        redColor.push(data[i]);
      } else {
        redColor.push(`<span style="color: red">${data[i]}</span>`);
      }
    }
    return redColor.join('');
  }
};