0부터 단어 연상 네트워크 구축

올해 여름에 내가 처음으로 launched개의 단어 도메인을 방문한 이래로 나는 이 사이트에서 끊임없이 증가하는 도메인 이름 목록을 조회하는 데 도움을 달라는 검색 기능에 대한 요청을 많이 받았다. (현재의 도메인 이름 수량은 약 500K)
이 기능의 구현을 계획하기 시작했을 때 첫 번째 생각은 다음과 같습니다.
이것은 너무 어렵지 않아야 한다. 나는 단지 다음과 같이 생각했다.
  • spaCy NLP library을 사용하여 사용자의 검색 조회와 가장 비슷한 단어 목록을 얻어 사이트에 표시합니다.
  • 에는 특정 질의에 사용할 수 있는 TLD 목록도 표시됩니다.
  • 별거 아니야.
    그러나 내가 나의 소망을 코드로 바꾸기 시작했을 때, 나는 기술적 제한에 부딪혔다.
    우선, 나는 검색 속도가 매우 빠르기를 원하기 때문에, 실시간으로 여현의 싱크로율을 계산하는 것은 불가능하다. 그것은 너무 오래 걸릴 뿐이다.
    또한 계산 시간을 <50ms로 최적화할 수 있어도 en_core_web_md모델 자체가 200MB를 초과할 때 spacy모델을 웹에 어떻게 배치합니까?
    나는 꼬박 3일이 걸려서야 실행 가능한 해결 방안을 생각해냈다. 이것이 바로 내가 이 블로그가 네가 더욱 짧은 시간 안에 이 점을 할 수 있도록 도와줄 수 있기를 바라는 이유이다.

    어휘 연상 네트워크를 구축하다.


    일련의 연구를 한 후에 나는 검색 시간을 50밀리초 이하로 줄일 수 있는 방법이 하나밖에 없다는 결론을 얻었다. 즉, 로컬 사전 훈련 모델에서 결과를 PostgreSQL에 저장할 수 있다는 것이다.
    기본적으로 내가 해야 할 일은 현재 데이터베이스에 있는 2만 개의 단어 간의 관계를 비추는 단어 관련 네트워크를 구축하는 것이다.
    상상해 보세요.

    참고: 각 모서리의 십진수 값은 보조 항목과 루트 사이의 유사성 분수를 나타냅니다.
    지금 다시 상상해 보세요. 하지만 이번에는 20000개의 형용사, 명사, 동사와 10개의 다른 종류+프랑스어와 스페인어 단어*가 있습니다.
    알아요. 미치고 멋있게 들리죠?
    먼저 가상 환경에 spacy 라이브러리를 설치하고 en_core_web_md 모델을 다운로드했습니다.
    pip install spacy
    python3 -m spacy download en_core_web_md
    
    그런 다음 Flask 응용 프로그램을 가져와 단어 벡터를 로드합니다.
    import spacy
    import en_core_web_md
    nlp = en_core_web_md.load()
    
    지금은 단어 관련 모델을 구축할 때다.나는 먼저 One Word Domains의 음성 목록을 가져와 그것들을 표시했다.그리고 플러그인 for 순환을 사용하여 나는 단어 사이의 여현 유사성을 계산했고 addToList 함수를 사용하여 단어마다 100개의 가장 비슷한 보조어 목록을 보존하고 모든 내용을 사전에 저장했다.이러한 모든 코드는 다음과 같습니다.
    # Add to list function to add the list of significant scores to list
    def addToList(ele, lst, num_ele):
        if ele in lst:
            return lst
        if len(lst) >= num_ele: #if list is at capacity
            if ele[1] > float(lst[-1][1]): #if element's sig_score is larger than smallest sig_score in list
                lst.pop(-1)
                lst.append((ele[0], str(ele[1])))
                lst.sort(key = lambda x: float(x[1]), reverse=True)
        else:
            lst.append((ele[0], str(ele[1])))
            lst.sort(key = lambda x: float(x[1]), reverse=True)
        return lst
    
    import json
    
    # list of English vocabs
    en_vocab = ['4k', 'a', 'aa', ...]
    
    # tokenizing the words in the vocab list
    tokens = nlp(' '.join(en_vocab))
    
    # initiate empty dictionary to store the results 
    en_dict = {}
    
    # Nested for loop to calculate cosine similarity scores
    for i in range(len(en_vocab)):
        word = en_vocab[i]
        print('Processing for '+ word + ' ('+ str(i) + ' out of '+ str(len(en_vocab)) + ' words)')
        for j in range(i+1, len(en_vocab)):
            prev_list_i = en_dict[str(tokens[i])]['similar_words']
            en_dict[str(tokens[i])]['similar_words'] = addToList((str(tokens[j]), tokens[i].similarity(tokens[j])), prev_list_i, 100)
            prev_list_j = en_dict[str(tokens[j])]['similar_words']
            en_dict[str(tokens[j])]['similar_words'] = addToList((str(tokens[i]), tokens[i].similarity(tokens[j])), prev_list_j, 100)
    
        with open('data.json', 'w') as f:
            json.dump(en_dict, f)
    
    이 코드는 운행하는 데 아주 오랜 시간이 걸렸다.20000개의 단어에 대해 모두 2000010000개의 조합(200000+19999+19998+...+3+2+1=20001*10000=200010000000)이 있다.모든 조합이 약 반 밀리초의 시간이 걸려야 완성할 수 있다는 것을 감안하면 전체 과정이 약 36시간이 걸려야 완성할 때 이상하지 않다.
    그러나 36시간의 힘든 작업이 끝난 후에 나는 단어 목록을 하나 만들었는데 단어마다 가장 비슷한 단어가 100개씩 있었다.
    데이터 검색 속도를 높이기 위해 저는 PostgreSQL에 데이터를 저장하기 시작했습니다. 이것은 믿을 수 없는 확장성과 강력한 기능을 가진 관계 데이터베이스입니다. 특히 대량의 데이터가 관련될 때입니다.나는 다음 코드 행을 통해 이 점을 실현했다.
    def store_db_postgres():
    
        with open('data.json', 'r') as f:
            data = json.load(f)
    
        for word in data.keys():
            db_cursor.execute("""INSERT INTO dbname (word, param) VALUES (%s, %s);""", (word, json.dumps(data[word]['similarity'])))
            db_conn.commit()
    
        return 'OK', 200
    
    봐라!현재, 당신은 최소한의 지연 상태에서 단어 관련 네트워크의 수백만 개의 가장자리를 통과할 수 있다. (내가 지난번에 검사했을 때, 그것은 50밀리초 이하의 수준에 있었다.)이 검색 도구는 현재 One Word Domains에 위치하고 있으며 마음대로 사용할 수 있습니다.
    *프랑스어와 스페인어 단어는 각각 fr_core_news_mdes_core_news_md 모형에서 훈련한다.

    클라우드에 배포


    까다로운 부분이 왔다.내 단어 관련 네트워크에는 가장 자주 사용하는 영어 단어가 2만 개가 넘지만 사용자의 조회는 내 지식 라이브러리에 속하지 않을 가능성이 있다는 것을 나는 안다.
    따라서 실행 중 결과를 생성할 수 있도록 사용자에게 옵션을 추가하고 싶습니다.이를 위해 스페이스 모델을 웹에 업로드해야 단어 관련 네트워크에 실시간으로 추가 테두리를 구축할 수 있습니다.
    그러나 이것은 Heroku에서 불가능하다. 왜냐하면 500MB의 피스톤 크기가 딱딱하기 때문이다. (나의 현재 피스톤 크기는 이미 300MB이다.)더 강력한 대안이 필요해서 AWS Lambda를 선택하기로 했습니다.
    내가 처음으로 Lambda 함수s를 만났을 때, 나는 그것들을 사용하여 movie chatbot의 NLP 구성 요소를 위탁 관리해야 했다. 이것은 내가 올해 가을에 나의 AI류를 위해 구축한 것이다.
    Lambda 함수는 처음에는 상당히 복잡하게 설정되었지만 편리한 Zappa library과 대량의 Stack Overflow 게시물의 도움으로 주어진 조회에 가장 비슷한 단어를 찾아 JSON 형식으로 되돌려주는 단어역 자체의 Lambda 함수를 구축할 수 있습니다.
    나는 배치 과정에 대해 깊이 토론하지 않겠지만, 이것은 guide으로 나에게 매우 큰 도움을 주었다.또한 지정된 질의에 가장 밀접한 연관이 있는 100개의 단어를 찾을 수 있는 주요 구동 함수도 있습니다.
    @app.route('/generate')
    @cross_origin()
    def generate_results():
        # get vocab
        vocab_pickle = s3.get_object(Bucket='intellisearch-assets', Key='vocab')['Body'].read()
        vocab_only = pickle.loads(vocab_pickle)
        vocab_only = list(set(vocab_only))
        # add new query to vocab
        vocab_only.insert(0, query)
        # store vocab back to pickle
        serialized_vocab = pickle.dumps(vocab_only)
        s3.put_object(Bucket='intellisearch-assets', Key='vocab', Body = serialized_vocab)
        # do the rest
        tokens = nlp(' '.join(vocab_only))
        results = []
        for i in range(1, len(vocab_only)):
            if str(tokens[i]) != query:
                results.append([str(tokens[i]), tokens[0].similarity(tokens[i])])
        results.sort(key=lambda x: x[1], reverse=True)
        return results[:100]
    
    여기에서, 나는pickle 파일 형식으로vocab 목록을AWS S3에 저장합니다. 새로운 검색이 있을 때마다, 나는 s3.get_obect 검색 목록을 사용하고, 새로운 단어를 목록에 삽입해서 업데이트합니다.Flask의 CORS 라이브러리에 있는 @cross_origin() 장식기를 사용하고 있습니다. 왜냐하면 Heroku 프로그램에서 이 Lambda 함수를 호출할 것입니다.
    그게 바로...별로 차이 안 나죠?내가 지금 해야 할 일은 AWS Lambda API 포트를 최초의 Heroku 응용 프로그램에 연결해서 사용자가 사이트에 입력한 주어진 검색 조회에 관련 단어의 목록을 만드는 데 도움을 주는 것이다.다음은 이 방면의 대강이다.
    import requests
    url = "https://my-api-endpoint.amazonaws.com/generate?query=" + query
    response = requests.get(url)
    similar_words = response.json()
    print(similar_words)
    
    마지막으로 중요한 순간입니다. 여기는 Loom recording이 있는데, 실시간 검색이 한 단어에서 어떻게 작동하는지 보여 줍니다.
    이것은 기능이 완비된 검색 알고리즘으로 20000개의 노드와 수백만 개의 변을 포함하는 단어 관련 네트워크 위에 세워졌다.
    페이지 맨 위에 있는 One Word Domains의 검색 도구를 마음대로 사용하십시오.만약 피드백이 있거나 버그를 발견하면 언제든지 채팅을 통해 저에게 메시지를 보내주세요. contact page, email 또는 - 기꺼이 도움을 드리겠습니다!

    좋은 웹페이지 즐겨찾기