Yeni tarix

Xatırladaq ki, dünyanın ən yaxşı futbolçularından biri və ya ən yaxşı futbolçudur.

tərəfindən Superlinked13m2025/04/25
Read on Terminal Reader

Çox uzun; Oxumaq

Çoğu e-ticarət təhlilçisi ya da çox statik (rule-based) ya da çox black-box (opac ML modelləri). Superlinked bir orta yol sunar: soğuk-start istifadəçilərə özəlləşdirilə bilər ki, metadata canlı davranışla birləşdirərək - bütün ML modelləri yeniləmək olmadan.
featured image - Xatırladaq ki, dünyanın ən yaxşı futbolçularından biri və ya ən yaxşı futbolçudur.
Superlinked HackerNoon profile picture
0-item
1-item


Şirkət

İnternet mağazalarınızın nə istədiyini nə etmədən bilsəydiniz?

Şirkət

İnternet mağazalarınızın nə istədiyini nə etmədən bilsəydiniz?


Most recommendation engines are like helpful but slightly clueless assistants:Onlar “populyar” və ya “başa-baxa” məlumatlara dayanır.struggleYeni istifadəçilər (soğuk başlanğıc problemi) və həqiqətdə bir istifadəçinin istəklərinin real vaxtda dəyişdiyi zaman çox az vaxt adaptasiya edirlər.


Əgər sisteminDüşünürəm həqiqətənMerchandiser kimi – statik məhsul verilərini və real-time istifadəçi davranışını birləşdirməkDoğru elementlərDoğru vaxtda nə?

Düşünürəm həqiqətən


This guide walks you through building a modern recommendation engineKullanışSuperlinkedBu, verilerinizi vektor-native infrastrukturu ilə işləyə biləcək, dəyişə biləcək istifadəçi profillərinə çevirərək bu tradicional ziyanları aşan bir profildir.


(Koduna doğrudan keçmək istəyirsənmi? GitHub-da açılmış kodu buradan izləyin. öz istifadə prosesi üçün rekommender sistemlərini test etmək üçün hazırsınızmı? burda demo alın.)

BuradaBuradaBuradaBurada


İnternetdə də bizimlə işləyə bilərsiniz.Kollektivlər


Təsadüfi: Dr

Çoğu e-ticarət təhlilçisi ya da çox statik (rule-based) ya da çox black-box (opac ML modelləri). Superlinked bir orta yol sunar: soğuk-start istifadəçilərə özəlləşdirilə bilər ki, metadata canlı davranışla birləşdirərək - bütün ML modelləri yeniləmək olmadan.

Rekonstruktiv problemlər olmasına baxmayaraq, bu problemlər

Vektor embeddings böyük ölçüde rekomandasiya sistemləri yaxşılaşdırmaq olsa da, onları etiraz etmək üçün bir çox problemləri həll etmək lazımdır:


    Şirkət
  • Qiymət və əsaslılıq: Yerləşdirilən generasiya prosesini, arhitekturu və məlumatları dikkatli düşünmək lazımdır.
  • Şirkət
  • VVD - Hollandiyada futbolçu bu adla tanımır, orada VVD daha çox mərkəz-sağı təmsilən edən siyasi partiyanın adının qısaltması kimi bilinir - artıq sorğu-suala ehtiyacı olmayan ulduzdu.
  • Şirkət
  • İstehsal edilə bilər: böyük datasetlər üçün effektiv metodlar lazımdır; yoxsa, latensiya bir problem olacaq.
  • Şirkət


Superlinked, istifadəçilər və məhsullar haqqında bütün imkanlı məlumatları geniş multimodal vektorlara birləşdirərək bu problemlərə cavab verməyə imkan verir.Aşağıdaki e-ticarət RecSys nümunəsində, aşağıdaki Superlinked kütləvi elementləri istifadə edirik:


    Şirkət
  • min_max sayı spaces: müştərilərin fikirləri və qiymətləndirilməsi üçün
  • Şirkət
  • Text-similarity Space: Ürün xəbərinin semantik anlayışı üçün
  • Şirkət
  • Vektorların dəyişdirilməsi üçün faktlar və efektlər
  • Şirkət
  • Soruşduğunuz zaman ağırlıqları - soruşduğunuz zaman verilərinizin necə işlənəcəyini, bütün veritabanı yenə daxil etmədən optimalizasiya və ölçüləməyə imkan verin (latenziyası)
  • Şirkət


Əvvəllər az sayda istifadəçi-spesifik verilərimizi (çox istifadəçinin ilk məhsul tercihini) daxil edərik, soğuk başlamaq problemini başa düşə bilərik.HipertansiyaSuperlinked-in sorğu vaxtı ağırlığı, aradan qaldırma nəticələrini düzəltsin, onları spesifik istifadəçi preferensiyalarına uyğunlaşdırmaq üçün ödənişlilaşdırır.


Let's get started!

Superlinked ilə e-ticarət rekomandasiyası motoru qurmaq

İnşaatın başlanğıcında isə belə bir şey var:product dataŞirkət :


    Şirkət
  • Revizorların sayı
  • Şirkət
  • Ürün Ratingləri
  • Şirkət
  • Tekstiqi Açıqlama
  • Şirkət
  • Ürün adı (bəzən markaların adı ilə bağlı)
  • Şirkət
  • Kategoriyada
  • Şirkət

Bizdə də aşağıdadata about users and productsŞirkət :


    Şirkət
  1. Hər bir müştərinin onlardan biri seçilir (t.y.
  2. Şirkət
  3. - istifadəçi davranışı (registrasiyadan sonra) məhsulların textual xüsusiyyətləri üçün preferensiyaları (bəqərə, adı, kategoriya)
  4. Şirkət

Buna görə də, klassik ekonomiya bizə deyir ki, ortalama, bütün istifadəçilər ceteris paribus:


    Şirkət
  • Daha az xərclənir
  • Şirkət
  • Bir çox recenziyalar
  • Şirkət
  • Daha yüksək qiymətlər
  • Şirkət

Biz bu verileri hesabatlandırmaq üçün Spaces-larımızı hazırlayırıq, belə ki, RecSys-lərimiz soğuk başlanma sahələrində işləyir - biz çox az bildiyimiz istifadəçilərə xəbərdarlıq verir.RecSys-lərimiz hazır və işlədikdə də davranış verilərimiz olacaq: istifadəçilər belirli məhsullara tıklayacaq, belirli məhsullar satın alacaq, etc. Biz bu xəbərdarlıq verilərini qurmaq üçün istifadə edə bilərik, vektorlarımızı istifadəçi preferensiyalarını yansıtmaq üçün güncellenə bilərik və rekomandasiyaların keyfiyyətini artırarıq.

Superlinklər yaratmaq

Birincisi, Superlinked kütləvi yükləmək və sınıfları import etmək lazımdır.


%pip install superlinked==6.0.0

import altair as alt
import os
import pandas as pd
import sys


from superlinked.framework.common.embedding.number_embedding import Mode
from superlinked.framework.common.schema.schema import schema
from superlinked.framework.common.schema.event_schema import event_schema
from superlinked.framework.common.schema.schema_object import String, Integer
from superlinked.framework.common.schema.schema_reference import SchemaReference
from superlinked.framework.common.schema.id_schema_object import IdField
from superlinked.framework.common.parser.dataframe_parser import DataFrameParser
from superlinked.framework.dsl.executor.in_memory.in_memory_executor import (
   InMemoryExecutor,
   InMemoryApp,
)
from superlinked.framework.dsl.index.index import Index
from superlinked.framework.dsl.index.effect import Effect
from superlinked.framework.dsl.query.param import Param
from superlinked.framework.dsl.query.query import Query
from superlinked.framework.dsl.source.in_memory_source import InMemorySource
from superlinked.framework.dsl.space.text_similarity_space import TextSimilaritySpace
from superlinked.framework.dsl.space.number_space import NumberSpace


alt.renderers.enable(get_altair_renderer())
pd.set_option("display.max_colwidth", 190)


Biz də datasetlərimizi tanımlayırıq və ən yaxşı 10 elementin depolanması üçün sabit yaratırıq - baxHücumu 3Notebook içində

Artıq kütüblərin yüklənmiş, import edilmiş sınıfları və datasetlərin yerlərini tanımladıqdan sonra, spaces-lərimizi qurduğumuzu bildirmək üçün datasetimizi izləyə bilərik.İlk olaraq, istifadəçi rejimindən olan verilərimiz var - ya da user_1 və user_2 üç məhsuldan hangisinin seçildiyi.


# the user preferences come from the user being prompted to select a product out of 3 - those will be the initial preferences
# this is done in order to give somewhat personalised recommendations
user_df: pd.DataFrame = pd.read_json(USER_DATASET_URL)
user_df


User product pref at registration


Biz də ürəklərimizin dağılım verilişlərinin yaxın araşdırmasını hazırlayırıq - baxHücumu 5Bu, sizə neçə-neçə məhsulların farklı qiyməti ilə bağlı olduğunu, fərqli qiymətləndirmə sayıları var və fərqli qiymətləndirmələr var (bunların əksəriyyəti bu rütbələrdədir).


Number of products vs price, review count, and rating distributions


Xatırladaq ki, bu barədə “Snickers” jurnalına istinadən xəbər verir ki, bu barədə “Snickers” jurnalına istinadən xəbər verir ki, “Snickers” jurnalına istinadən xəbər verir ki, “Snickers” jurnalına istinadən xəbər verir ki, “Snickers” jurnalına istinadən xəbər verilir.Şirkətlər 7-9İŞİD

Vektor araması üçün indeksi qurmaq

Superlinked'in kütləvi, indeksləri qurmaq və aradan qaldırmaq üçün istifadə etdiyimiz bazar bina bloklarının bir hissəsini içerməlidir.BuradaİŞİD


Bu kitabxananın yaradıcılıq bloklarını EComm RecSys-də istifadə edəcəyik.define your SchemaSisteminizə xəbər verin.


# schema is the way to describe the input data flowing into our system - in a typed manner
@schema
class ProductSchema:
   description: String
   name: String
   category: String
   price: Integer
   review_count: Integer
   review_rating: Integer
   id: IdField

@schema
class UserSchema:
   preference_description: String
   preference_name: String
   preference_category: String
   id: IdField

@event_schema
class EventSchema:
   product: SchemaReference[ProductSchema]
   user: SchemaReference[UserSchema]
   event_type: String
   id: IdField

# we instantiate schemas as follows
product = ProductSchema()
user = UserSchema()
event = EventSchema()


Sonradan, "Spaces"ı istifadə edin, verilərinizin hər bir hissəsini daxil etməkdə necə işləmək istəyirsiniz. "Space definitions"da, inputların verilərimizdəki semantika əlaqələrini yansıtması üçün nasıl daxil ediləcəyini yazırıq.


# textual inputs are embedded in a text similarity space powered by a sentence_transformers model
description_space = TextSimilaritySpace(
   text=[user.preference_description, product.description],
   model="sentence-transformers/all-distilroberta-v1",
)
name_space = TextSimilaritySpace(
   text=[user.preference_name, product.name],
   model="sentence-transformers/all-distilroberta-v1",
)
category_space = TextSimilaritySpace(
   text=[user.preference_category, product.category],
   model="sentence-transformers/all-distilroberta-v1",
)

# NumberSpaces encode numeric input in special ways to reflect a relationship
# here we express relationships to price (lower the better), or ratings and review counts (more/higher the better)
price_space = NumberSpace(
   number=product.price, mode=Mode.MINIMUM, min_value=25, max_value=1000
)
review_count_space = NumberSpace(
   number=product.review_count, mode=Mode.MAXIMUM, min_value=0, max_value=100
)
review_rating_space = NumberSpace(
   number=product.review_rating, mode=Mode.MAXIMUM, min_value=0, max_value=4
)

# create the index using the defined spaces
product_index = Index(
   spaces=[
       description_space,
       name_space,
       category_space,
       price_space,
       review_count_space,
       review_rating_space,
   ]
)

# parse our data into the schemas - not matching column names can be conformed to schemas using the mapping parameter
product_df_parser = DataFrameParser(schema=product)
user_df_parser = DataFrameParser(
   schema=user, mapping={user.preference_description: "preference_desc"}
)

# setup our application
source_product: InMemorySource = InMemorySource(product, parser=product_df_parser)
source_user: InMemorySource = InMemorySource(user, parser=user_df_parser)
executor: InMemoryExecutor = InMemoryExecutor(
   sources=[source_product, source_user], indices=[product_index]
)
app: InMemoryApp = executor.run()

# load the actual data into our system
source_product.put([products_df])
source_user.put([user_df])


Artıq verilerinizi Spaces-da tanımladığınızda, verilərinizlə oynamaq və sonuçları optimize etmək üçün hazırsınız.Evlər olmadan nə edə bilərik?Soğuk başlanğıcımız var.

RecSys “Cold-Start” problemini həll etmək

Burada, yalnız istifadəçinin tercih vektoru ilə arama edən bir istifadəçi sorğusu tanımlayırıq.Biz hər bir giriş tipinin (Spaş) önəminin (çoxlarının) konfigürasiyasını kontrol edirik.


user_query = (
   Query(
       product_index,
       weights={
           description_space: Param("description_weight"),
           name_space: Param("name_weight"),
           category_space: Param("category_weight"),
           price_space: Param("price_weight"),
           review_count_space: Param("review_count_weight"),
           review_rating_space: Param("review_rating_weight"),
       },
   )
   .find(product)
   .with_vector(user, Param("user_id"))
   .limit(Param("limit"))
)

# simple recommendations for our user_1
# these are based only on the initial product the user chose when first entering our site
simple_result = app.query(
   user_query,
   user_id="user_1",
   description_weight=1,
   name_weight=1,
   category_weight=1,
   price_weight=1,
   review_count_weight=1,
   review_rating_weight=1,
   limit=TOP_N,
)

simple_result.to_pandas()


Bu sorğunun nəticələri, user_1-in ilk dəfə eComm saytımızda kayıtlaşdıqları zaman bir çanta seçdiyi gerçəkdir.


User 1 registration product choice-based recs


Ümumilikdə user_1 üçün istifadə etmək mümkündür.Genel olaraq“Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin” “Qəbələ”nin “Qəbələ”nin” “Qəbələ”nin “QəbələBiz də bu ağırlıqlarla oynayırıq ki, bir Space və ya başqa bir Space yönündə nəticələri düzəltsin.


general_result = app.query(
   user_query,
   user_id="user_1",
   description_weight=0,
   name_weight=0,
   category_weight=0,
   price_weight=1,
   review_count_weight=1,
   review_rating_weight=1,
   limit=TOP_N,
)

general_result.to_pandas() 



General product features-based recs

Yeni bir istifadəçi araması sorğunun texti bizim rekomandasiya nəticələrimiz üçün bir giriş kimi təqdim edir - baxHücumu 20İŞİD

"Uşaqlar üçün ən faydalı oyunlar" - "Uşaqlar üçün ən faydalı oyunlar" - "Uşaqlar üçün ən faydalı oyunlar" - "Uşaqlar üçün ən faydalı oyunlar" - "Uşaqlar üçün ən faydalı oyunlar" - "Uşaqlar üçün ən faydalı oyunlar" - "Uşaqlar üçün ən faydalı oyunlar" - "Uşaqlar üçün ən faydalı oyunlar" - "Uşaqlar üçün ən faydalı oyunlar"additional weight to the category space(ə)category_weight = 10Qadınlar üçün daha çox “çəkiliş” məhsulları təqdim edirik.


women_cat_result = app.query(
   search_query,
   user_id="user_1",
   query_text="women clothing jackets",
   description_weight=1,
   name_weight=1,
   category_weight=10,
   price_weight=1,
   review_count_weight=1,
   review_rating_weight=1,
   limit=TOP_N,
)

women_cat_result.to_pandas()


Qadınlar üçün daha çox imkan var, daha çox qadınlar üçün daha çox imkan var.


User 1 query for "women clothing jackets" recs.png


Əsas səhifə > Ürünlər > Dərslər > Dərslər > Dərslər (review_rating_weight=5Xatırladaq ki, bu, bir neçə ildir ki, ABŞ-ın baş məşqçiləri, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatlar, diplomatHücumu 22İŞİD

Personalized Experiences yaratmaq üçün Event Data istifadə etmək

Bizim istifadəçilərimiz platformamızla mübahisə etmişlər - user_1 daha çox, user_2 daha az.behavioral dataAşağıda qeyd olunan hadisələr var:

    Şirkət
  • Təsadüfi və rekreativ məhsullara ehtiyacı olan bir istifadəçi (user_2)
  • Şirkət
  • İş yerindən çıxmaq və formal iş vaxtı üçün elegant məhsullara ehtiyacı olan bir istifadəçi (user_1)
  • Şirkət
events_df = (
   pd.read_json(EVENT_DATASET_URL)
   .reset_index()
   .rename(columns={"index": "id"})
   .head(NROWS)
)
events_df = events_df.merge(
   products_df[["id"]], left_on="product", right_on="id", suffixes=("", "r")
).drop("idr", axis=1)
events_df = events_df.assign(created_at=1715439600)

events_df


user events

Xahiş edirik ki, istifadəçilərin bir məhsulla olan ilgisini qeyd etmək üçün spesifik əməllər ağırlaşır və aradan qaldırmaq sırasında olayları dərk etmək üçün setupı dəyişir.

event_weights = {
   "clicked_on": 0.2,
   "buy": 1,
   "put_to_cart": 0.5,
   "removed_from_cart": -0.5,
}

# adjust the setup to events
product_index_with_events = Index(
    spaces=[
        description_space,
        category_space,
        name_space,
        price_space,
        review_count_space,
        review_rating_space,
    ],
    effects=[
        Effect(
            description_space,
            event.user,
            event_weight * event.product,
            event.event_type == event_type,
        )
        for event_type, event_weight in event_weights.items()
    ]
    + [
        Effect(
            category_space,
            event.user,
            event_weight * event.product,
            event.event_type == event_type,
        )
        for event_type, event_weight in event_weights.items()
    ]
    + [
        Effect(
            name_space,
            event.user,
            event_weight * event.product,
            event.event_type == event_type,
        )
        for event_type, event_weight in event_weights.items()
    ],
)
event_df_parser: DataFrameParser = DataFrameParser(schema=event)
source_event: InMemorySource = InMemorySource(schema=event, parser=event_df_parser)
executor_with_events: InMemoryExecutor = InMemoryExecutor(
    sources=[source_product, source_user, source_event],
    indices=[product_index_with_events],
)
app_with_events: InMemoryApp = executor_with_events.run()


Artıq yeni bir indeks yaratırıq ki, istifadəçilərin olaylarını hesabatlandırsın, sonra hər bir istifadəçi üçün tamamilə rekomandasiyaları kişiselleştirək.

# for a new index, all data has to be put into the source again
source_product.put([products_df])
source_user.put([user_df])
source_event.put([events_df])

# a query only searching with the user's vector the preferences are now much more personalised thanks to the events
personalised_query = (
   Query(
       product_index_with_events,
       weights={
           description_space: Param("description_weight"),
           category_space: Param("category_weight"),
           name_space: Param("name_weight"),
           price_space: Param("price_weight"),
           review_count_space: Param("review_count_weight"),
           review_rating_space: Param("review_rating_weight"),
       },
   )
   .find(product)
   .with_vector(user, Param("user_id"))
   .limit(Param("limit"))
)


“RexSys” sistemimizdə olayların yerləşdirilməsinin effektini kişiselleştirmə ağırlaşdırılması ilə gözləyirik.Sadəcə bir azvə yaAğırBirincisi, görək, bu (vaxtiliyin verilişləri) olayları ilə bağlı olan spazmları ağırlaşdırmanın effektini (baseline qarşı) görək.

# with small weight on event-affected spaces, we mainly just alter the results below position 4
general_event_result = app_with_events.query(
   personalised_query,
   user_id="user_1",
   description_weight=1,
   category_weight=1,
   name_weight=1,
   price_weight=1,
   review_count_weight=1,
   review_rating_weight=1,
   limit=TOP_N,
)

general_event_result.to_pandas().join(
   simple_result.to_pandas(), lsuffix="", rsuffix="_base"
)[["description", "id", "description_base", "id_base"]]


Əvvəlki məqalədəDünyanın baş məşqçisiyindən biri olan “Dünyanın baş məşqçisidir” – “Dünyanın baş məşqçisidir” – “Dünyanın baş məşqçisidir” – “Dünyanın baş məşqçisidir” – “Dünyanın baş məşqçisidir” – “Dünyanın baş məşqçisidir”


Slightly weighted events-affected spaces vs baseline


Amma əgər biz olaydan etkilənmiş spazmları daha ağır hiss edəriksə, rekomandasiya listamızda tamamilə yeni elementlər yerləşdirərik.


# with larger weight on the the event-affected spaces, more totally new items appear in the TOP10
event_weighted_result = app_with_events.query(
   personalised_query,
   user_id="user_1",
   query_text="",
   description_weight=5,
   category_weight=1,
   name_weight=1,
   price_weight=1,
   review_count_weight=1,
   review_rating_weight=1,
   limit=TOP_N,
)

event_weighted_result.to_pandas().join(
   simple_result.to_pandas(), lsuffix="", rsuffix="_base"
)[["description", "id", "description_base", "id_base"]]


More heavily weighted events-affected spaces vs baseline


Bəlkə də, konkret bir istifadəçi davranışına (bağışlanma data) uyğunlaşdırmaq üçün ağırlıqları istifadə edə bilərik.Başqa məhsullar üçün prioritetBirincisi, qiyməti görməkHücumu 31İŞİD

Sonrakı

EComm RecSys-in Superlinked kütləvi (yani) implementasiyası, vektor embeddings gücünü istifadəçilərin sorğu və davranış verilərinin semantik anlamını birləşdirərək necə əldə edə biləcəyini göstərir. min_max sayı və texta bənzərliyi spaces, Events şeması və effektləri və sorğu vaxt ağırlıqları ilə, RecSys-in soğuk başlama, keyfiyyət, əsaslılıq və ölçüləbilicilik problemlərini həll edə bilərsiniz və üretimdə yüksək həddi aşan, istifadəçilər üçün kişiselleştirilmiş qərarlar verə bilərsiniz.

Artıq sizin vaxtınızdır!Superlinked kütləvi özünüzü bizim notebooklarımızı istifadə edinİŞİD

Try It Yourself – Get the Code & Demo!

Bunu özünüz də deneyin – Code & Demo alın!
    Şirkət
  • Kodu alın: GitHub repo-ndəki tam quruluşu burda görün.Fork onu, tweak onu, və özünüz olsun!
  • Şirkət
  • Xatırladaq ki, “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”da “Supernatural”
  • Şirkət
BuradaBuradaİŞİD

“Rekomendation engines are shaping the way we discover content.Whether it’s popular pants, music, or other products.vector search is the future- Artıq sizin özünüzü yaratmaq üçün cihazlarınız var.

Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks