Nam's

[신발검색엔진] 09 - 검색 알고리즘 개선 본문

카테고리 없음

[신발검색엔진] 09 - 검색 알고리즘 개선

namespace 2021. 7. 24. 14:47

첫 코드에서는 mysql "LIKE" 를 이용해서 상품 제목이나 브랜드이름에 검색 keyword가 "포함"되어 있으면 보여주게 했다.
다음과 같은 문제들이 발생한다.

1. 검색 키워드가 띄어쓰기를 포함해 완벽히 포함되어야한다.
     ex) DB에 상품 제목이 "에어 맥스" 인데, 사용자가 "나이키 에어 맥스" 라고 검새하면 검색되지 않는다.
2. 브랜드가 영어로만 표기되어 있다.
     ex) 나이키라고 치면 안나오고, nike라고 쳐야된다.

1번 문제 해결을 위해서 사용자 검색 keyword를 음절 단위로 분해하고 검색을 진행했다. 더 좋은 검색 알고리즘을 위해서는 형태소 단위로 분해할 수도 있겠지만, 신발 검색 엔진에 불필요한 조사를 포함해 검색하는 경우가 많을 것 같지는 않다. (데이터를 모아볼 필요는 있겠다.)

def find_items_with_keywords(keywords):
    keyword_list = keywords.split()

    for i in range(len(keyword_list)):
        keyword_list[i] = "%" + keyword_list[i] + "%"

    output = Item.query\
        .join(Brand, Item.brand==Brand.eng_name)\
        .add_columns(Item.title, Item.brand, Brand.subs, Item.image_url, Item.item_url, Item.price, Item.shop, Item.title)

    for i in range(len(keyword_list)):
        output = output.filter(Item.title.like(keyword_list[i]) | Item.brand.like(keyword_list[i]) | Brand.subs.like(keyword_list[i]))
        
    output = output.limit(max_item_num).all()
    output = items_schema.dump(output)

    return output

2번 문제 해결을 위해서 무신사 브랜드관에서 모든 브랜드의 영문 이름과 한글 이름을 저장했다.

class MusinsaBrandCrawler(Resource):
    def get(self):
        driver = webdriver.Chrome(os.getcwd() + "/chromedriver")
        driver.get("https://store.musinsa.com/app/contents/brandshop")

        time.sleep(2)

        brand_list = driver.find_elements_by_tag_name("dl")
        

        for brand in brand_list:
            eng_name = brand.text.split(' SALE')[0]
            #subs = brand.text.splitlines()[1] #.split(' (')[0]

            if len(brand.text.splitlines()) == 2:
                eng_name = brand.text.splitlines()[0]
                subs = brand.text.splitlines()[1]

                if eng_name.find(' SALE') > -1:
                    eng_name = eng_name[0:eng_name.find(' SALE')]
                if eng_name.find(' 단독') > -1:
                    eng_name = eng_name[0:eng_name.find(' 단독')]
                if subs.find(' (') > -1:
                    subs = subs[0:subs.find(' (')]

                # print(eng_name, eng_name.lower(), subs)

                try:
                    new_brand = Brand(
                        eng_name = eng_name.lower(),
                        subs = subs
                    )

                    db.session.add(new_brand)
                    db.session.commit()

                except Exception as e:
                    print(e)
                    pass

        driver.close()

 

프로젝트를 진행하면서, 가장 중요한 것은 "좋은 크롤러"를 만드는 것임을 느낀다. 내가 알고 사용하던 크롤러는 너무 좁은 범위의 크롤러였고, robots.txt도 고려하지 않는 비윤리적인 크롤러였다. 다른 작업들을 하기에 앞서서 크롤링을 더 공부해야겠다.

다음은 현재 참고하여 공부 중인 크롤링 관련 글들이다.

'웹 크롤러' 좀 그만 만들어라
웹 크롤링과 아키텍쳐
https://www.google.com/intl/ko/search/howsearchworks/crawling-indexing/

 

Comments