使用LSH算法和Minhash在类似Omegle的应用程序中实现等待机制。

huangapple go评论61阅读模式
英文:

Implementing a waiting mechanism in an application similar to Omegle using LSH algorithm and Minhash

问题

我正在开发一个类似于Omegle的应用程序,用户根据共同兴趣与陌生人匹配。为了实现这一目标,我正在将LSH(局部敏感哈希)算法与Minhash技术结合使用。然而,在实现用户调用API后不能立即找到匹配对的等待机制时,我遇到了困难。

目前,我正在使用sleep函数来引入等待时间,然后返回“失败”的状态。然而,似乎sleep函数会阻塞其他API调用,并导致其他用户的延迟。我想知道像Omegle这样的网站如何处理这种情况,以及如何正确实施有效的等待机制的正确步骤。

以下是代码片段:

from fastapi import FastAPI, Body
from typing import Annotated
from pydantic import BaseModel
from sonyflake import SonyFlake
import redis
import time
from datasketch import MinHash, MinHashLSH

app = FastAPI()
sf = SonyFlake()
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
lsh = MinHashLSH(num_perm=128, threshold=0.5, storage_config={
    'type': 'redis',
    'redis': {'host': '127.0.0.1', 'port': 6379}
}, prepickle=True)

class Partner(BaseModel):
    client_id: int
    partner_id: str
    status: str = 'Failed';

@app.post("/start", response_model=Partner)
async def start(interests: Annotated[list[str] | None, Body()] = None) -> Partner:
    client_id=sf.next_id()
    partner_id = ''

    minhash = MinHash()
    if not interests:
        return Partner(client_id = client_id, partner_id = partner_id)

    client_hash = f"user:{client_id}:interests:hash"
    minhash.update_batch([*(map(lambda item: item.encode('utf-8'), interests))])
    lsh.insert(client_hash, minhash)

    matches = lsh.query(minhash)
    matches.remove(client_hash)

    if not matches:
        time.sleep(5)

    matches = lsh.query(minhash)
    matches.remove(client_hash)

    if not matches:
        lsh.remove(client_hash)
        return Partner(client_id = client_id, partner_id = partner_id)

    lsh.remove(client_hash)
    lsh.remove(matches[0])
    return Partner(client_id = client_id, partner_id = matches[0], status="Success")

我将不断尝试匹配,如果没有匹配,将会休眠5秒钟,然后再次尝试匹配。如果仍然没有匹配,返回"Failed"状态。

请分享有关在这种情况下如何有效实施等待机制的任何见解或建议,确保不会对应用程序的性能和响应性产生负面影响。在维护API对其他用户的响应性的同时,是否有推荐的方法或最佳实践来实现这一功能?

  • 请提供有关在这种情况下实施有效等待机制的见解或最佳实践。
  • 任何关于优化代码或提高响应性的建议将不胜感激。
  • 请提供更多阅读材料或链接。

谢谢。

英文:

I'm developing an application similar to Omegle, where users are matched with strangers based on their common interests. To achieve this, I'm combining the LSH (Locality Sensitive Hashing) algorithm with the Minhash technique. However, I'm facing difficulties in implementing a waiting mechanism for users who don't immediately find a matching pair when they call the API.

Currently, I'm using the sleep function to introduce a waiting period before returning the status "Failed". However, it seems that the sleep function is blocking other API calls and causing delays for other users. I'm curious to know how websites like Omegle handle this scenario and what would be the correct procedure to implement an efficient waiting mechanism.

Here's code snippet:

from fastapi import FastAPI, Body
from typing import Annotated
from pydantic import BaseModel
from sonyflake import SonyFlake
import redis
import time
from datasketch import MinHash, MinHashLSH

app = FastAPI()
sf = SonyFlake()
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
lsh = MinHashLSH(num_perm=128, threshold=0.5, storage_config={
    'type': 'redis',
    'redis': {'host': '127.0.0.1', 'port': 6379}
}, prepickle=True)


class Partner(BaseModel):
    client_id: int
    partner_id: str
    status: str = 'Failed'


@app.post("/start", response_model=Partner)
async def start(interests: Annotated[list[str] | None, Body()] = None) -> Partner:
    client_id=sf.next_id()
    partner_id = ''

    minhash = MinHash()
    if not interests:
        return Partner(client_id = client_id, partner_id = partner_id)

    client_hash = f"user:{client_id}:interests:hash"
    minhash.update_batch([*(map(lambda item: item.encode('utf-8'), interests))])
    lsh.insert(client_hash, minhash)

    matches = lsh.query(minhash)
    matches.remove(client_hash)

    if not matches:
        time.sleep(5)

    matches = lsh.query(minhash)
    matches.remove(client_hash)

    if not matches:
        lsh.remove(client_hash)
        return Partner(client_id = client_id, partner_id = partner_id)

    lsh.remove(client_hash)
    lsh.remove(matches[0])
    return Partner(client_id = client_id, partner_id = matches[0], status="Success")

I would appreciate any insights or suggestions on how to properly implement the waiting mechanism, ensuring that it doesn't negatively impact the performance and responsiveness of the application. Is there a recommended approach or best practice to achieve this functionality while maintaining the responsiveness of the API for other users?

  • Please share any insights or best practices on implementing an efficient waiting mechanism in this scenario.
  • Any suggestions on optimizing the code or improving its responsiveness would be greatly appreciated.
  • Please provide resources or links to read more about it.

Thank you.

答案1

得分: 1

根据我所了解的情况,似乎您正在实现一个同步等待机制,这会阻塞整个进程。您应该考虑使用一种轮询或异步的方式。这可以通过WebSocket或HTTP长轮询来实现。我认为WebSocket 在许多方面更好,主要是双向通信和保持连接的原因。我已经为您尝试实现了这一点:

from fastapi import FastAPI, WebSocket, Body, Depends
from typing import Annotated
from pydantic import BaseModel
from sonyflake import SonyFlake
import redis
from datasketch import MinHash, MinHashLSH
import asyncio

app = FastAPI()
sf = SonyFlake()
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
lsh = MinHashLSH(num_perm=128, threshold=0.5, storage_config={
    'type': 'redis',
    'redis': {'host': '127.0.0.1', 'port': 6379}
}, prepickle=True)

class Partner(BaseModel):
    client_id: int
    partner_id: str
    status: str = 'Failed'

@app.post("/start", response_model=Partner)
async def start(interests: Annotated[list[str] | None, Body()] = None) -> Partner:
    client_id = sf.next_id()
    partner_id = ''
    
    minhash = MinHash()
    if not interests:
        return Partner(client_id=client_id, partner_id=partner_id)
    
    client_hash = f"user:{client_id}:interests:hash"
    minhash.update_batch([*(map(lambda item: item.encode('utf-8'), interests))])
    lsh.insert(client_hash, minhash)
    
    return Partner(client_id=client_id, partner_id=partner_id)

@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: int):
    await websocket.accept()
    while True:
        client_hash = f"user:{client_id}:interests:hash"
        minhash = lsh.get(client_hash)
        
        if minhash is None:
            await websocket.send_json({"status": "Error", "message": "Client ID not found"})
            return
    
        matches = lsh.query(minhash)
        matches.remove(client_hash)
    
        if not matches:
            await websocket.send_json({"status": "Waiting"})
        else:
            lsh.remove(client_hash)
            lsh.remove(matches[0])
            await websocket.send_json({"status": "Success", "client_id": client_id, "partner_id": matches[0]})
            return
        await asyncio.sleep(5)

希望这有助于您的项目!

英文:

From what I can tell, it seems like you're implementing a synchronous waiting mechanism, which is blocking the entire process. You should look into using a form of polling or asynch. This can be done through a WebSocket or through HTTP long-polling. I think WebSockets are better for a few reasons, but mostly bi-diretional comms and keep-alive conns. I have tried to implement for that for you below:

from fastapi import FastAPI, WebSocket, Body, Depends
from typing import Annotated
from pydantic import BaseModel
from sonyflake import SonyFlake
import redis
from datasketch import MinHash, MinHashLSH
app = FastAPI()
sf = SonyFlake()
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
lsh = MinHashLSH(num_perm=128, threshold=0.5, storage_config={
'type': 'redis',
'redis': {'host': '127.0.0.1', 'port': 6379}
}, prepickle=True)
class Partner(BaseModel):
client_id: int
partner_id: str
status: str = 'Failed'
@app.post("/start", response_model=Partner)
async def start(interests: Annotated[list[str] | None, Body()] = None) -> Partner:
client_id=sf.next_id()
partner_id = ''
minhash = MinHash()
if not interests:
return Partner(client_id = client_id, partner_id = partner_id)
client_hash = f"user:{client_id}:interests:hash"
minhash.update_batch([*(map(lambda item: item.encode('utf-8'), interests))])
lsh.insert(client_hash, minhash)
return Partner(client_id = client_id, partner_id = partner_id)
@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: int):
await websocket.accept()
while True:
client_hash = f"user:{client_id}:interests:hash"
minhash = lsh.get(client_hash)
if minhash is None:
await websocket.send_json({"status": "Error", "message": "Client ID not found"})
return
matches = lsh.query(minhash)
matches.remove(client_hash)
if not matches:
await websocket.send_json({"status": "Waiting"})
else:
lsh.remove(client_hash)
lsh.remove(matches[0])
await websocket.send_json({"status": "Success", "client_id": client_id, "partner_id": matches[0]})
return
await asyncio.sleep(5)

huangapple
  • 本文由 发表于 2023年5月24日 18:21:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76322466.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定