Tìm giải pháp: phân loại, xếp hạng nội dung theo thời gian thực ???



  • Chào các bạn, mình đang mắc khoản thuật toán để xếp hạng nội dung (hot, trend) không biết xử lý ra sao, mong các pro đi qua chỉ giáo dùm.
    Mình có 1 data được log lại trong khoảng thời gian 1h như sau:

    var postData = [
        {
          id: 1,
          view: 254,
          like: 20,
          bookmark: 0,
          shared: 2
        },
        {
          id: 2,
          view: 68,
          like: 30,
          bookmark: 1,
          shared: 2
        },
        {
          id: 3,
          view: 20,
          like: 5,
          bookmark: 1,
          shared: 0
        },
        {
          id: 4,
          view: 1000,
          like: 0,
          bookmark: 0,
          shared: 0
        }
     ];
    

    Với xếp hạng dựa trên 1 cơ sở (vd view) có thể dùng z-score để sắp xếp, nhưng nếu sử dụng 2 hoặc nhiều hơn các cơ sở (vd view, like, bookmark, shared...) để xếp hạng thì không rõ phải sử dụng thuật toán như thế nào ???



  • theo ý kiến cá nhân: xếp hạng độ quan trọng của đề mục trước , shared > bookmark > like > view
    shared 10point, bookmark: 5point ....
    rồi dựa vào đấy tinh toán thôi



  • Vấn đề là target của bạn khi xếp hạng hot trend là gi. Ví dụ như bạn muốn tối đa hoá lượt view. Bạn có thể dụng mô hình linear regresssion trong machine learning.
    để tính toán. Để làm việc này khá đơn giản thôi, mỗi item thì có 4 features là shared, bookmark, like, view trong 1 ngày trước đó chẻn hạn, và số lượt view của của nó trong ngày hôm nay là label. Từ đó tìm 1 hàm số có dạng y = x*theta' hợp lí nhất. Từ đó tìm được các trọng số của nó. Sau đó áp dụng vào tính thôi y , sort là xong.



  • Theo em thì anh dùng kernel(SVM) xem sao



  • theo mình hiểu ý của bạn là xếp hạng từng cái riêng biệt đúng không ?

    mình vừa soạn cho bạn một mẫu example xem có giúp được gì không !

    OUPUT 1

    
    var view = new Search(postData, "like").LTH();
    console.log("Thấp Đến Cao by like",view) ;
    /*
    [
        {"id":4,"view":1000,"like":0,"bookmark":0,"shared":0},                
        {"id":3,"view":20,"like":5,"bookmark":1,"shared":0},
        {"id":1,"view":254,"like":20,"bookmark":0,"shared":2},
        {"id":2,"view":68,"like":30,"bookmark":1,"shared":2}
    ]
    */
    

    OUTPUT 2

    var view = new Search(postData, "like",true).Group();
    console.log("Thấp Đến Cao Group by like", view);
    
    {
        "id":[4,3,1,2],
        "view":[1000,20,254,68],
        "like":[0,5,20,30],
        "bookmark":[0,1,0,1],
        "shared":[0,0,2,2]
    }
    

    CODE Example

    const postData = [{
            id: 1,
            view: 254,
            like: 20,
            bookmark: 0,
            shared: 2
        },
        {
            id: 2,
            view: 68,
            like: 30,
            bookmark: 1,
            shared: 2
        },
        {
            id: 3,
            view: 20,
            like: 5,
            bookmark: 1,
            shared: 0
        },
        {
            id: 4,
            view: 1000,
            like: 0,
            bookmark: 0,
            shared: 0
        }
    ];
     
    class Search {
    
        /**
         ** @param {Object} InputDB => Nhập vào là danh sách [ {a:1,b:2},{a:2,b:1} ]
         ** @param {String} SearchBy => cần search cái gì trong danh sách :) 
         ** @param {Booleans} Sort => True thì Search.Group sort LTH || false thì HTL
         ** @example new Search([ {a:1,b:2},{a:2,b:1} ],"a",true).LTH()
         ** @example new Search([ {a:1,b:2},{a:2,b:1} ],"a",true).Group()
         **/
        constructor(InputDB, SearchBy,Sort) {
            this.InputDB = InputDB;
            this.SearchBy = SearchBy;
            this.Sort = Sort;
        }
        
        Group() {
            let Data;
            let Group = {};
            if (this.Sort) {
              Data =  this.LTH()
            }else{
              Data =  this.HTL()
            }
            Data.map(a => {
                Object.keys(a).forEach(db => {
                    if (!Group[db]) Group[db] = new Array();
                    Group[db].push(a[db])
                })
            })
            return Group;
        }
        
        LTH() {
            return this.InputDB.sort((a, b) => {
                return a[this.SearchBy] - b[this.SearchBy];
            });
        }
    
        HTL() {
            return this.InputDB.sort((a, b) => {
                return b[this.SearchBy] - a[this.SearchBy];
            });
        }
    }
    
    


  • Quan trọng là mục tiêu -> kiếm trọng số -> Cho vào cái sort :))))

    Nguyen (Rodgers) Hien.
    Sent from Wood-PC.

    0


  • Bác có thể dựa vào key : view & like xỉ số %n tương đồng cho ra hot trend của id đó :v



  • Update Example phân loại xếp hạng theo group cho thêm lựa chọn !



  • @Hồ-Duy-Quốc-Bảo thanks bạn, mình đang muốn sắp xếp (xếp hạng) dựa trên 2 hoặc nhiều hơn cơ sở.

    vd: để biết được topic nào trên nodejs.vn đang có xu hướng tốt:

    • view (base)
    • upvote/downvote
    • reply.
    1. topic nếu lượng view nhiều nhưng downvote > upvote & ko có reply
    2. topic lượng view trung bình, upvote = downvote, reply nhiều
    3. topic lượng view trung bình, upvote > downvote, reply it
    var topics = [
    	{
    		id: 1,
    		view: 100,
    		upvote: 5,
    		downvote: 10,
    		reply: 0,
    	},
    	{
    		id: 2,
    		view: 30,
    		upvote: 5,
    		downvote: 5,
    		reply: 12,
    	},
    	{
    		id: 3,
    		view: 32,
    		upvote: 5,
    		downvote: 2,
    		reply: 6,
    	},
    ];
    

    Phân loại ra chính xác topic-2 đang hot vì lượng reply có xu hướng tăng > view + > up/down vote tăng. Nếu chỉ dựa vào 1 cơ sở (view chẳng hạn) thì có thể không phản ánh đúng topic mọi người đang quan tâm (vào rồi ra cũng là 1 view rồi).

    Mình đang thử 2 suggest của @Cao-Kỳ-Hãn vs @hatran9-6 , hi vọng 2 bạn có thể giải thích cụ thể hơn.



  • để mình viết thử thuật toán khác xem sao !



  • đây theo ý bạn ! nhưng mình không xếp hạng thằng view vào vì view có thể sẽ làm rối đội hình thuật tiên đoán
    mình chỉ có theerv hỗ trợ bạn như thế này !
    (a[upvote]+a[downvote]+a[reply] ) - (b[upvote]+b[downvote]+b[reply] ) so sánh danh sách điểm số thằng nào đạt yêu cầu cao nhất thì sẽ hiển thị đầu tiên.
    vì người vào xem không vote hoặc repy thì khó lên topic HOT được hoặc bị flood view 1 phát thì loạn cả DB!
    còn việc downvote hay upvote không cần thiết phải so sánh cứ cộng down,up,reply lại vì 3 thằng đó là mấu chốt của người dùng

    const topics = [{
        id: 1,
        view: 100,
        upvote: 5,
        downvote: 10,
        reply: 0,
    }, {
        id: 2,
        view: 30,
        upvote: 5,
        downvote: 5,
        reply: 12,
    }, {
        id: 3,
        view: 32,
        upvote: 5,
        downvote: 2,
        reply: 6,
    }, ];
    class Search {
    
        /**
         ** @param {Object} InputDB => Nhập vào là danh sách [ {a:1,b:2},{a:2,b:1} ]
         ** @param {String} SearchBy => cần search cái gì trong danh sách :) 
         ** @param {Booleans} Sort => True thì Search.Group sort LTH || false thì HTL
         ** @example new Search([ {a:1,b:2},{a:2,b:1} ],"a",true).LTH()
         ** @example new Search([ {a:1,b:2},{a:2,b:1} ],"a",true).Group() 
         **/
        constructor(InputDB, SearchBy, Sort) {
            this.InputDB = InputDB;
            this.SearchBy = SearchBy;
            this.Sort = Sort;
        }
    
        Group() {
            let Data;
            let Group = {};
            if (this.Sort) {
                Data = this.LTH()
            }
            else {
                Data = this.HTL()
            }
            Data.map(a => {
                Object.keys(a).forEach(db => {
                    if (!Group[db]) Group[db] = new Array();
                    Group[db].push(a[db])
                })
            })
            return Group;
        }
        Mixin(a, b, c) {
            let n1 = 0;
            let n2 = 0;
            for (const key in a) {
                n1 += b[a[key]];
                n2 += c[a[key]];
            }
            return n1 - n2
        }
        LTH() {
            const seft = this;
            const TypeOf = (typeof seft.SearchBy).toLowerCase();
    
            if (TypeOf === "object") {
    
                return seft.InputDB.sort((a, b) => {
                    return seft.Mixin(this.SearchBy, a, b);
                })
            }
        }
    
        HTL() {
            const seft = this;
            const TypeOf = (typeof seft.SearchBy).toLowerCase();
    
            if (TypeOf === "object") {
    
                return seft.InputDB.sort((a, b) => {
                    return seft.Mixin(this.SearchBy, b, a);
                })
            }
        }
    }
    

    **Example he ! **

    
    console.log(new Search(topics, ["upvote", "downvote", "reply"], true).HTL());
    
    [
        {
            "id": 2,
            "view": 30,
            "upvote": 5,
            "downvote": 5,
            "reply": 12
        }, {
            "id": 1,
            "view": 100,
            "upvote": 5,
            "downvote": 10,
            "reply": 0
        }, {
            "id": 3,
            "view": 32,
            "upvote": 5,
            "downvote": 2,
            "reply": 6
        }
    ]
    
    console.log(new Search(topics, ["upvote", "downvote", "reply"], true).LTH());
    [
        {
            "id": 3,
            "view": 32,
            "upvote": 5,
            "downvote": 2,
            "reply": 6
        }, {
            "id": 1,
            "view": 100,
            "upvote": 5,
            "downvote": 10,
            "reply": 0
        }, {
            "id": 2,
            "view": 30,
            "upvote": 5,
            "downvote": 5,
            "reply": 12
        }
    ]
    
    console.log(new Search(topics, ["upvote", "downvote", "reply"], true).Group());
        {
            "id": [3, 1, 2],
            "view": [32, 100, 30],
            "upvote": [5, 5, 5],
            "downvote": [2, 10, 5],
            "reply": [6, 0, 12]
        }


  • @Martin-Pham đã tìm Hot/Trend thì phải có dữ liệu theo thời gian. với dữ liệu bạn đưa ra thì gọi là sắp xếp theo field thôi.



  • @hidemanvn Như mình đã nói ở đầu topic, dữ liệu giả định được log trong 1h mà bạn.



  • @Hồ-Duy-Quốc-Bảo giải pháp bạn đưa ra gần giống với cách reddit đang sử dụng:

    cpdef long score(long ups, long downs):
        return ups - downs
    
    cpdef double hot(long ups, long downs, date):
        return _hot(ups, downs, epoch_seconds(date))
    
    cpdef double _hot(long ups, long downs, double date):
        """The hot formula. Should match the equivalent function in postgres."""
        s = score(ups, downs)
        order = log10(max(abs(s), 1))
        if s > 0:
            sign = 1
        elif s < 0:
            sign = -1
        else:
            sign = 0
        seconds = date - 1134028003
        return round(sign * order + seconds / 45000, 7)
    


  • @Hồ-Duy-Quốc-Bảo bạn viết code có dài quá ko. Bạn có thể kế thừa LTH HTL. Bạn có thể dùng một lần bắt lỗi duy nhất. Và ko nhất thiết phải tạo class



  • @Ann-Nguyễn
    mỗi người có cách viết khác nhau mà bạn !
    mình thích thì mình viết thôi ,miễn sao public rõ ràng mạch lạc người đọc hiểu và chức năng cần thiết vừa đủ.
    code gà nên hơi dài ....


Log in to reply