다국어 웹사이트를 위한 간단한 검색 엔진(Gwoogl :p) 구축

23187 단어 noderestapijavascript
사용자 생성 콘텐츠가 많은 웹 사이트는 최근 여러 언어를 채택하고 지원하기 시작했습니다! 저는 이것이 훌륭하다고 생각합니다. 왜냐면 기본적으로 왜 안되죠? 제 말은 이것이 인터넷의 시작부터 그랬어야 한다는 것입니다, 그렇죠? 그러나 어쨌든, 그들 중 일부는 "제목", "태그", "설명"과 같은 "목록"텍스트 콘텐츠에 의존하여 전체 콘텐츠를 색인화한 다음 후속 방문자를 위한 내부 검색 엔진을 제공합니다.

그중에서 우리는 미디어 콘텐츠(이미지 및 비디오)가 사용자에게 전달되는 원시 가치인 웹사이트를 보유하고 있습니다(제가 말하는 내용을 짐작하셨을 것입니다 😉). 따라서 "날씬한 대 뚱뚱한 레슬링"🙃을 찾는 방문자는 제목, 태그 및 설명이 무엇이든 모든 미디어에 관심을 갖고 검색에 빠지는 것을 인정할 것입니다. 예, 이 사례는 특히 증가하고 있습니다. 이러한 웹 사이트를 가지고 있고 다국어 검색 지원을 시작하지 않았다면 여기에서 출발점을 찾을 수 있습니다.

먼저 NodeJS를 웹 서버로 사용하고 MongoDB를 데이터베이스로 사용합니다. 이는 Word to Word API의 이점을 설명하기 위한 매우 기본적인 의미입니다.

    // define your base query
    const baseQuery = { d: false, a: true }
    /**
     * Approximate multilingual search based on indexed text fields: title, desc, tags
     * @param {*} phrase sentence to search
     * @param {*} exact whether search the exact sentence or separate terms
     * @param {*} otherFields Of course you can add any other categorical fields to search
     * @param {*} lang which language the phrase is in
     * @return {Promise}
     */
    this.gwoogl = async function (phrase, exact, otherFields, lang) {
        // Limit search to newer content (ignoring very old content)
        const daysBefore = 100
        collection = mongoDB.collection('listing')
        const since = getObjectId(daysBefore)
        // quoted string value in Mongo to look for the exact match ! 
        phrase = exact ? `"${phrase.trim()}"` : phrase.trim()
        const query = JSON.parse(JSON.stringify(baseQuery)) // clone
        // Collation is very important, it helps Mongo with searching natural languages
        // something like "a car" can spot either "the car", "cars" etc
        // Note that Collation at the moment is an index on the whole collection, ie
        // You cannot apply different collation(s) on documents
        let collation = lang === 'und' ? baseCollation : { locale: lang }

        // THE FOLLOWING IS AN EXAMPLE 
        // HERE I'M FIRST SEARCHING FOR THE WHOLE PHRASE AS IS
        // THEN I CALL TRANSLATION API ON THE FIRST TERM IN THE PHRASE. YOU CAN ITERATE ON EACH WORD IN THE SAME MANNER !!
        // STACK AND FORMAT RESULTS AS YOU WISH !

        query.$text = { $search: phrase }
        query._id = { $gt: since }
        if (lang !== 'und') query.lang = lang
        // Dynamically adding other fields
        for (const [key, value] of Object.entries(otherFields)) {
            if (value !== 'und') query[key] = value
        }
        const docs = await collection
            .find(query, { score: { $meta: 'textScore' } })
            .collation(collation)
            .project(baseProjection)
            .sort({ score: { $meta: 'textScore' } })
            .limit(21)
            .toArray()
        const count = await collection.countDocuments(query)
        const result = { documents: docs, count: count, crossLangDocs: [] }

        if (count < 6 && phrase.indexOf(' ') < 0) {
            // Call translate API on each keyword, grab each query result (keywords), concatenate them as a single phrase and query again
            let translations = translate({ limit: 10, source: lang, score: '0.5', word: phrase, target: 'fr', target: 'es', target: 'fi' })
            for (const [lang, keywords] of Object.entries(translations)) {
                collation = { locale: lang }
                // Concatenating translations as a single phrase (you can do however you feel better) 
                phrase = keywords.join(' ')
                query.$text = { $search: phrase }
                const crossLangDocs = await collection
                    .find(query, { score: { $meta: 'textScore' } })
                    .collation(collation)
                    .project(baseProjection)
                    .sort({ score: { $meta: 'textScore' } })
                    .limit(3)
                    .toArray()
                // console.log(crossLangDocs)
                crossLangDocs.forEach((doc) => {
                    doc['crosslang'] = lang
                })
                result.crossLangDocs = result.crossLangDocs.concat(crossLangDocs)
            }
        }
        return result
    }



// Helpers

/**
 * This function returns an ObjectId embedded with a given dateTime
 * Accepts number of days since document was created
 * Author: https://stackoverflow.com/a/8753670/1951298
 * @param {Number} days
 * @return {object}
 */
function getObjectId(days) {
    const yesterday = new Date()
    days = days || (process.env.NODE_ENV === 'localhost' ? 1000 : 14)
    yesterday.setDate(yesterday.getDate() - days)
    const hexSeconds = Math.floor(yesterday / 1000).toString(16)
    return new ObjectId(hexSeconds + '0000000000000000')
}



고려하다




    // Indexing title and description fields (ie fields to search for)
    // collection#text must be indexed as the following:
    const listingCollection = db.collection('listing')
    await listingCollection.dropIndexes()
    await listingCollection.createIndex({ title: 'text', cdesc: 'text' }, { weights: { title: 3, cdesc: 1 } })




// APIWrapper.js
// Requst Word to Word translator API

/*
* API wrapper
*
*/

import axios from "axios";

const translateParameters = (params) => {
    return {
        method: 'GET',
        url: 'https://word-to-word-translator1.p.rapidapi.com/api/translate',
        params,
        headers: { 'X-RapidAPI-Key': 'YOUR RAPID API GOES HERE' }
    }
};

const detectParameters = (params) => {
    return {
        method: 'GET',
        url: 'https://word-to-word-translator1.p.rapidapi.com/api/detect_language',
        params,
        headers: { 'X-RapidAPI-Key': 'YOUR RAPID API GOES HERE' }
    }
};


const translate = async (params) => {
    return await axios.request(translateParameters(params))
}

const detect = async (params) => {
    return await axios.request(detectParameters(params))
}

export { translate, detect }


최종 참고 사항



간단한 검색 엔진을 구축하는 것이 쉽지 않다는 것을 알 수 있습니다. 역시 자연어가 포함되기 때문입니다. 그러나 동시에 "인하우스"로 구축된 성능 솔루션은 매우 가능합니다!!
매우 작은 Gwoogl 검색 엔진을 사용하는 시나리오는 다음과 같습니다.

1- 사용자 입력 받기(실시간일 수 있음(솔직히 가능하다고 생각하지만 개인적으로 성능을 확인하기 위해 시도하지는 않음))
2- 일부 데이터 정리 및 조정(어간 추출, 표제어 추출 등)을 수행할 수 있습니다. 고맙게도 우리의 언어 감지 및 번역은 이와 관련하여 매우 강력하며 문맥 검색을 사용하므로 예를 들어 복수형을 그대로 두는 것이 좋습니다!
3- 입력 언어 감지( Word2Word#detect )
4- 입력 단어 번역( Word2Word#translate )
5- 키워드를 반복하고 결과를 쌓으세요!

만세, 이제 다국어 검색 엔진이 생겼습니다!

좋은 웹페이지 즐겨찾기