Elasticsearch:介绍 kNN query,这是进行 kNN 搜索的专家方法

news2024/11/15 17:52:47

作者:来自 Elastic Mayya Sharipova, Benjamin Trent

当前状况:kNN 搜索作为顶层部分

Elasticsearch 中的 kNN 搜索被组织为搜索请求的顶层(top level)部分。 我们这样设计是为了:

  • 无论分片数量多少,它总是可以返回全局 k 个最近邻居
  • 这些全局 k 个结果与其他查询的结果相结合以形成混合搜索
  • 全局 k 结果被传递到聚合以形成统计(facets)。

这是 kNN 搜索在内部执行的简化图(省略了一些阶段):

图 1:顶层 kNN 搜索的步骤是:

  1. 用户提交搜索请求
  2. 协调器节点在 DFS 阶段向数据节点发送请求的 kNN 搜索部分
  3. 每个数据节点运行 kNN 搜索并将本地 top-k 结果发送回协调器
  4. 协调器合并所有本地结果以形成全局前 k 个最近邻居。
  5. 协调器将全局 k 个最近邻居发送回数据节点,并提供任何其他查询
  6. 每个数据节点运行额外的查询并将本地 size 结果发送回协调器
  7. 协调器合并所有本地结果并向用户发送响应

我们首先在 DFS 阶段运行 kNN 搜索以获得全局前 k 个结果。 然后,这些全局 k 结果被传递到搜索请求的其他部分,例如其他查询或聚合。 即使执行看起来很复杂,但从用户的角度来看,运行 kNN 搜索的模型很简单,因为用户始终可以确保 kNN 搜索返回全局 k 结果。

它的请求格式如下:

GET collection-with-embeddings/_search
{
  "knn": {
    "field": "text_embedding.predicted_value",
    "query_vector_builder": {
      "text_embedding": {
        "model_id": "sentence-transformers__msmarco-distilbert-base-tas-b",
        "model_text": "How is the weather in Jamaica?"
      }
    },
    "k": 10,
    "num_candidates": 100
  },
  "_source": [
    "id",
    "text"
  ]
}

引入 kNN 查询

随着时间的推移,我们意识到还需要将 kNN 搜索表示为查询。 查询是 Elasticsearch 中搜索请求的核心组件,将 kNN 搜索表示为查询可以灵活地将其与其他查询结合起来,以解决更复杂的请求。

kNN 查询与顶层 kNN 搜索不同,没有 k 参数。 与其他查询一样,返回的结果(最近邻居)的数量由 size 参数定义。 与 kNN 搜索类似,num_candidates 参数定义在执行 kNN 搜索时在每个分片上考虑多少个候选者。

GET products/_search
{
 "size" : 3,
 "query": {
   "knn": {
     "field": "embedding",
     "query_vector": [2,2,2,0],
     "num_candidates": 10
   }
 }
}

kNN 查询的执行方式与顶层 kNN 搜索不同。 下面是一个简化图,描述了 kNN 查询如何在内部执行(省略了一些阶段):

图 2:基于查询的 kNN 搜索步骤如下:

  • 用户提交搜索请求
  • 协调器向数据节点发送一个 kNN 搜索查询,并提供附加查询
  • 每个数据节点运行查询并将本地大小结果发送回协调器节点
  • 协调器节点合并所有本地结果并向用户发送响应

我们在一个分片上运行 kNN 搜索以获得 num_candidates 结果; 这些结果将传递给分片上的其他查询和聚合,以从分片获取大小结果。 由于我们不首先收集全局 k 个最近邻居,因此在此模型中,收集的且对其他查询和聚合可见的最近邻居的数量取决于分片的数量。

kNN 查询 API 示例

让我们看一下 API 示例,这些示例演示了顶层 kNN 搜索和 kNN 查询之间的差异。

我们创建产品索引并索引一些文档:

PUT products
{
 "mappings": {
   "dynamic": "strict",
   "properties": {
     "department": {
       "type": "keyword"
     },
     "brand": {
       "type": "keyword"
     },
     "description": {
       "type": "text"
     },
     "embedding": {
       "type": "dense_vector",
       "index": true,
       "similarity": "l2_norm"
     },
     "price": {
       "type": "float"
     }
   }
 }
}
POST products/_bulk?refresh=true
{"index":{"_id":1}}
{"department":"women","brand": "Levi's", "description":"high-rise red jeans","embedding":[1,1,1,1],"price":100}
{"index":{"_id":2}}
{"department":"women","brand": "Calvin Klein","description":"high-rise beautiful jeans","embedding":[1,1,1,1],"price":250}
{"index":{"_id":3}}
{"department":"women","brand": "Gap","description":"every day jeans","embedding":[1,1,1,1],"price":50}
{"index":{"_id":4}}
{"department":"women","brand": "Levi's","description":"jeans","embedding":[2,2,2,0],"price":75}
{"index":{"_id":5}}
{"department":"women","brand": "Levi's","description":"luxury jeans","embedding":[2,2,2,0],"price":150}
{"index":{"_id":6}}
{"department":"men","brand": "Levi's", "description":"jeans","embedding":[2,2,2,0],"price":50}
{"index":{"_id":7}}
{"department":"women","brand": "Levi's", "description":"jeans 2023","embedding":[2,2,2,0],"price":150}

kNN 查询类似于顶层 kNN 搜索,具有 num_candidates 和充当预过滤器的内部 filter 参数。

GET products/_search?filter_path=**.hits
{
 "size" : 3,
 "query": {
   "knn": {
     "field": "embedding",
     "query_vector": [2,2,2,0],
     "num_candidates": 10,
     "filter" : {
       "term" : {
         "department" : "women"
       }
     }
   }
 }
} 
{
  "hits": {
    "hits": [
      {
        "_index": "products",
        "_id": "4",
        "_score": 1,
        "_source": {
          "department": "women",
          "brand": "Levi's",
          "description": "jeans",
          "embedding": [
            2,
            2,
            2,
            0
          ],
          "price": 75
        }
      },
      {
        "_index": "products",
        "_id": "5",
        "_score": 1,
        "_source": {
          "department": "women",
          "brand": "Levi's",
          "description": "luxury jeans",
          "embedding": [
            2,
            2,
            2,
            0
          ],
          "price": 150
        }
      },
      {
        "_index": "products",
        "_id": "7",
        "_score": 1,
        "_source": {
          "department": "women",
          "brand": "Levi's",
          "description": "jeans 2023",
          "embedding": [
            2,
            2,
            2,
            0
          ],
          "price": 150
        }
      }
    ]
  }
}

kNN 查询比 kNN collapsing 和聚合搜索可以获得更多样化的结果。 对于下面的 kNN 查询,我们在每个分片上执行 kNN 搜索以获得 10 个最近邻居,然后将其传递到 collapsing 以获取 3 个顶部结果。 因此,我们将在响应中得到 3 个不同的点击。

GET products/_search?filter_path=**.hits
{
 "size" : 3,
 "query": {
   "knn": {
     "field": "embedding",
     "query_vector": [2,2,2,0],
     "num_candidates": 10,
     "filter" : {
       "term" : {
         "department" : "women"
       }
     }
   }
 },
 "collapse": {
   "field": "brand"        
 }
}
{
  "hits": {
    "hits": [
      {
        "_index": "products",
        "_id": "4",
        "_score": 1,
        "_source": {
          "department": "women",
          "brand": "Levi's",
          "description": "jeans",
          "embedding": [
            2,
            2,
            2,
            0
          ],
          "price": 75
        },
        "fields": {
          "brand": [
            "Levi's"
          ]
        }
      },
      {
        "_index": "products",
        "_id": "2",
        "_score": 0.2,
        "_source": {
          "department": "women",
          "brand": "Calvin Klein",
          "description": "high-rise beautiful jeans",
          "embedding": [
            1,
            1,
            1,
            1
          ],
          "price": 250
        },
        "fields": {
          "brand": [
            "Calvin Klein"
          ]
        }
      },
      {
        "_index": "products",
        "_id": "3",
        "_score": 0.2,
        "_source": {
          "department": "women",
          "brand": "Gap",
          "description": "every day jeans",
          "embedding": [
            1,
            1,
            1,
            1
          ],
          "price": 50
        },
        "fields": {
          "brand": [
            "Gap"
          ]
        }
      }
    ]
  }
}

顶层 kNN 搜索首先在 DFS 阶段获取全局前 3 个结果,然后在查询阶段将它们传递到 collapse。 我们在响应中只会得到 1 个命中,因为全球 3 个最近的邻居恰好都来自同一品牌。

与聚合类似,kNN query 允许我们获得 3 个不同的存储桶,而 kNN search 仅允许 1 个。

GET products/_search?filter_path=aggregations
{
"size": 0,
"query": {
   "knn": {
     "field": "embedding",
     "query_vector": [2,2,2,0],
     "num_candidates": 10,
     "filter" : {
       "term" : {
         "department" : "women"
       }
     }
   }
 },
 "aggs": {
   "brands": {
     "terms": {
       "field": "brand"
     }
   }
 }
}
{
  "aggregations": {
    "brands": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "Levi's",
          "doc_count": 4
        },
        {
          "key": "Calvin Klein",
          "doc_count": 1
        },
        {
          "key": "Gap",
          "doc_count": 1
        }
      ]
    }
  }
}

而顶层的 search 是这样的:

GET products/_search?filter_path=aggregations
{
  "size": 0,
  "knn": {
    "field": "embedding",
    "query_vector": [
      2,
      2,
      2,
      0
    ],
    "k": 3,
    "num_candidates": 10,
    "filter": {
      "term": {
        "department": "women"
      }
    }
  },
  "aggs": {
    "brands": {
      "terms": {
        "field": "brand"
      }
    }
  }
}
{
  "aggregations": {
    "brands": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "Levi's",
          "doc_count": 3
        }
      ]
    }
  }
}

现在,让我们看一下其他示例,展示 kNN 查询的灵活性。 具体来说,它如何能够灵活地与其他查询结合起来。

kNN 可以是 boolean 查询的一部分(需要注意的是,所有外部查询过滤器都用作 kNN 搜索的后过滤器)。 我们可以使用 kNN 查询的 _name 参数来通过额外信息来增强结果,这些信息告诉 kNN 查询是否匹配及其分数贡献。

GET products/_search?include_named_queries_score
{
 "size": 3,
 "query": {
   "bool": {
     "should": [
       {
         "knn": {
           "field": "embedding",
           "query_vector": [2,2,2,0],
           "num_candidates": 10,
           "_name": "knn_query"
         }
       },
       {
         "match": {
           "description": {
             "query": "luxury",
             "_name": "bm25query"
           }
         }
       }
     ]
   }
 }
}
{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 7,
      "relation": "eq"
    },
    "max_score": 2.8042283,
    "hits": [
      {
        "_index": "products",
        "_id": "5",
        "_score": 2.8042283,
        "_source": {
          "department": "women",
          "brand": "Levi's",
          "description": "luxury jeans",
          "embedding": [
            2,
            2,
            2,
            0
          ],
          "price": 150
        },
        "matched_queries": {
          "knn_query": 1,
          "bm25query": 1.8042282
        }
      },
      {
        "_index": "products",
        "_id": "4",
        "_score": 1,
        "_source": {
          "department": "women",
          "brand": "Levi's",
          "description": "jeans",
          "embedding": [
            2,
            2,
            2,
            0
          ],
          "price": 75
        },
        "matched_queries": {
          "knn_query": 1
        }
      },
      {
        "_index": "products",
        "_id": "6",
        "_score": 1,
        "_source": {
          "department": "men",
          "brand": "Levi's",
          "description": "jeans",
          "embedding": [
            2,
            2,
            2,
            0
          ],
          "price": 50
        },
        "matched_queries": {
          "knn_query": 1
        }
      }
    ]
  }
}

kNN 也可以是复杂查询的一部分,例如 pinned 查询。 当我们想要显示最接近的结果,但又想要提升选定数量的其他结果时,这非常有用。

GET products/_search
{
 "size": 3,
 "query": {
   "pinned": {
     "ids": [ "1", "2" ],
     "organic": {
       "knn": {
           "field": "embedding",
           "query_vector": [2,2,2,0],
           "num_candidates": 10,
           "_name": "knn_query"
         }
     }
   }
 }
}
{
  "took": 9,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 7,
      "relation": "eq"
    },
    "max_score": 1.7014124e+38,
    "hits": [
      {
        "_index": "products",
        "_id": "1",
        "_score": 1.7014124e+38,
        "_source": {
          "department": "women",
          "brand": "Levi's",
          "description": "high-rise red jeans",
          "embedding": [
            1,
            1,
            1,
            1
          ],
          "price": 100
        },
        "matched_queries": [
          "knn_query"
        ]
      },
      {
        "_index": "products",
        "_id": "2",
        "_score": 1.7014122e+38,
        "_source": {
          "department": "women",
          "brand": "Calvin Klein",
          "description": "high-rise beautiful jeans",
          "embedding": [
            1,
            1,
            1,
            1
          ],
          "price": 250
        },
        "matched_queries": [
          "knn_query"
        ]
      },
      {
        "_index": "products",
        "_id": "4",
        "_score": 1,
        "_source": {
          "department": "women",
          "brand": "Levi's",
          "description": "jeans",
          "embedding": [
            2,
            2,
            2,
            0
          ],
          "price": 75
        },
        "matched_queries": [
          "knn_query"
        ]
      }
    ]
  }
}

我们甚至可以将 kNN 查询作为 function_score 查询的一部分。 当我们需要为 kNN 查询返回的结果定义自定义分数时,这非常有用:​

GET products/_search
{
 "size": 3,
 "query": {
   "function_score": {
     "query": {
       "knn": {
           "field": "embedding",
           "query_vector": [2,2,2,0],
           "num_candidates": 10,
           "_name": "knn_query"
         }
     },
     "functions": [
       {
         "filter": { "match": { "department": "men" } },
         "weight": 100
       },
       {
         "filter": { "match": { "department": "women" } },
         "weight": 50
       }
     ]
   }
 }
}
{
  "took": 3,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 7,
      "relation": "eq"
    },
    "max_score": 100,
    "hits": [
      {
        "_index": "products",
        "_id": "6",
        "_score": 100,
        "_source": {
          "department": "men",
          "brand": "Levi's",
          "description": "jeans",
          "embedding": [
            2,
            2,
            2,
            0
          ],
          "price": 50
        },
        "matched_queries": [
          "knn_query"
        ]
      },
      {
        "_index": "products",
        "_id": "4",
        "_score": 50,
        "_source": {
          "department": "women",
          "brand": "Levi's",
          "description": "jeans",
          "embedding": [
            2,
            2,
            2,
            0
          ],
          "price": 75
        },
        "matched_queries": [
          "knn_query"
        ]
      },
      {
        "_index": "products",
        "_id": "5",
        "_score": 50,
        "_source": {
          "department": "women",
          "brand": "Levi's",
          "description": "luxury jeans",
          "embedding": [
            2,
            2,
            2,
            0
          ],
          "price": 150
        },
        "matched_queries": [
          "knn_query"
        ]
      }
    ]
  }
}

当我们想要组合 kNN 搜索和其他查询的结果时,kNN 查询作为 dis_max 查询的一部分非常有用,以便文档的分数来自排名最高的子句,并为任何其他子句提供打破平局的增量。

GET products/_search
{
 "size": 5,
 "query": {
   "dis_max": {
     "queries": [
       {
         "knn": {
           "field": "embedding",
           "query_vector": [2,2, 2,0],
           "num_candidates": 3,
           "_name": "knn_query"
         }
       },
       {
         "match": {
           "description": "high-rise jeans"
         }
       }
     ],
     "tie_breaker": 0.8
   }
 }
}
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 7,
      "relation": "eq"
    },
    "max_score": 1.890432,
    "hits": [
      {
        "_index": "products",
        "_id": "1",
        "_score": 1.890432,
        "_source": {
          "department": "women",
          "brand": "Levi's",
          "description": "high-rise red jeans",
          "embedding": [
            1,
            1,
            1,
            1
          ],
          "price": 100
        }
      },
      {
        "_index": "products",
        "_id": "2",
        "_score": 1.890432,
        "_source": {
          "department": "women",
          "brand": "Calvin Klein",
          "description": "high-rise beautiful jeans",
          "embedding": [
            1,
            1,
            1,
            1
          ],
          "price": 250
        }
      },
      {
        "_index": "products",
        "_id": "4",
        "_score": 1.0679927,
        "_source": {
          "department": "women",
          "brand": "Levi's",
          "description": "jeans",
          "embedding": [
            2,
            2,
            2,
            0
          ],
          "price": 75
        },
        "matched_queries": [
          "knn_query"
        ]
      },
      {
        "_index": "products",
        "_id": "6",
        "_score": 1.0679927,
        "_source": {
          "department": "men",
          "brand": "Levi's",
          "description": "jeans",
          "embedding": [
            2,
            2,
            2,
            0
          ],
          "price": 50
        },
        "matched_queries": [
          "knn_query"
        ]
      },
      {
        "_index": "products",
        "_id": "5",
        "_score": 1.0556482,
        "_source": {
          "department": "women",
          "brand": "Levi's",
          "description": "luxury jeans",
          "embedding": [
            2,
            2,
            2,
            0
          ],
          "price": 150
        },
        "matched_queries": [
          "knn_query"
        ]
      }
    ]
  }
}

kNN 搜索作为查询已在 8.12 版本中引入。 请尝试一下,如果有任何反馈,我们将不胜感激。

原文:Introducing kNN query, an expert way to do kNN search — Elastic Search Labs

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1404242.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【人工智能大脑】仿生学与人工智能交汇:基于MP神经网络的精准农业实践

MP神经网络,即McCulloch-Pitts模型(MCP Model),是神经网络的早期形式之一,由Warren McCulloch和Walter Pitts在1943年提出。这个模型为现代人工神经网络的发展奠定了理论基础,并首次尝试模拟了生物神经元的…

Kotlin程序设计 扩展篇(一)

Kotlin程序设计(扩展一) **注意:**开启本视频学习前,需要先完成以下内容的学习: 请先完成《Kotlin程序设计》视频教程。请先完成《JavaSE》视频教程。 Kotlin在设计时考虑到了与Java的互操作性,现有的Ja…

RK3568 移植Ubuntu

使用ubuntu-base构建根文件系统 1、到ubuntu官网获取 ubuntu-base-18.04.5-base-arm64.tar.gz Ubuntu Base 18.04.5 LTS (Bionic Beaver) 2、将获取的文件拷贝到ubuntu虚拟机,新建目录,并解压 mkdir ubuntu_rootfs sudo tar -xpf u

Ubuntu之离线安装Gitlab,搭建私有代码仓库

Ubuntu之离线安装Gitlab,搭建私有代码仓库 文章目录 Ubuntu之离线安装Gitlab,搭建私有代码仓库1. 官网下载:2. 安装Gitlab3. 使用 1. 官网下载: https://packages.gitlab.com/gitlab/gitlab-ce wget下载地址: wget https://packages.gitla…

Linux命令_vim的详细用法

简介 vim是一款针对Linux和其他类Unix操作系统的文本编辑器。它是Vi编辑器的升级版本,具有丰富的功能和强大的扩展性。vim有三种基本模式:命令模式、插入模式和可视模式。 命令模式:用户可以使用各种命令移动光标和进行编辑操作,如…

安裝火狐和穀歌流覽器插件FoxyProxy管理海外動態IP代理

代理生態系統擁有大量有用的實用程式,使海外代理IP代理設置的使用變得簡單起來。其中一種類型叫做代理管理工具,像FoxyProxy就是該工具集比較受歡迎的。 本文將全面解析FoxyProxy擴展的功能和特性、Foxyproxy怎麼下載、以及如何在穀歌流覽器和火狐流覽器…

数据分析的理念、流程、方法、工具(上)

一、数据的价值 1、数据驱动企业运营 从电商平台的「猜你喜欢」到音乐平台的「心动模式」,大数据已经渗透到了我们生活的每一个场景。不论是互联网行业,还是零售业、制造业等,各行各业都在依托互联网大数据(数据采集、数据存储、…

AutoDL——终端训练神经网络模型(忽略本地问题)

前言: 本人之前分享过一篇文章:使用pycharm连接远程GPU训练神经网络模型(超详细!),其中详细介绍了如何利用pycharm连接AutoDL算力云平台租用的GPU服务器训练网络模型。但有些小伙伴可能会因为一些原因而导…

清越 peropure·AI 国内版ChatGP新功能介绍

当OpenAI发布ChatGPT的时候,没有人会意识到,新一代人工智能浪潮将给人类社会带来一场眩晕式变革。其中以ChatGPT为代表的AIGC技术加速成为AI领域的热门发展方向,推动着AI时代的前行发展。面对技术浪潮,清越科技(PeroPure)立足多样化生活场景、精准把握用户实际需求,持续精确Fin…

【爬虫、数据可视化实战】以“人口”话题为例爬取实时微博数据并进行舆情分析

前言: 近期在weibo上讨论的比较热的话题无非就是“人口”了。TaoTao也看了一些大家发的内容。但是感觉单纯的看文字内容不能很直观的反应出来大家的关切。索性就使用爬虫对数据进行爬取,同时结合着数据可视化的方式让数据自己开口说话。那么接下来就让我…

浮点数详解

目录 1.概述 2.浮点数的编码方式 2.1.float类型的IEEE编码 2.2.double类型的IEEE编码 2.3.现场问题 2.4.总结 1.概述 计算机也需要运算和存储数学中的实数。在计算机的发展过程中,曾产生过多种存储实数的方式,有的现在已经很少使用了。不管如何存储…

OpenCV书签 #差值哈希算法的原理与相似图片搜索实验

1. 介绍 差值哈希算法(Difference Hash Algorithm,简称dHash) 是哈希算法的一种,主要可以用来做以图搜索/相似图片的搜索工作。 2. 原理 差值哈希算法通过计算相邻像素的差异来生成哈希,即通过缩小图像的每个像素与平…

macbookpro怎么恢复出厂设置2024最新恢复方法汇总

可能你的MacBook曾经是高性能的代表,但是现在它正慢慢地逝去了自己的光芒?随着逐年的使用以及文件的添加和程序的安装,你的MacBook可能会开始变得迟缓卡顿,或者失却了以往的光彩。如果你发现你的Mac开始出现这些严重问题&#xff…

c#中使用UTF-8编码处理多语言文本的有效策略

使用UTF-8编码处理多语言文本的有效策略 在当今的全球化时代,软件开发者常常需要处理包含多种语言的文本。这不仅涉及英文和其他西方语言,还包括中文、日文、韩文等多字节字符系统。在这篇博客中,我将探讨如何有效地使用UTF-8编码来处理混合语…

基于SpringBoot Vue二手闲置物品交易系统

大家好✌!我是Dwzun。很高兴你能来阅读我,我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结,还为大家分享优质的实战项目,本人在Java项目开发领域有多年的经验,陆续会更新更多优质的Java实战项目&#x…

unity shaderGraph实例-武器特效(纹理遮罩,纹理动画,纹理变形)

文章目录 效果展示所需素材整体结构各区域内容区域1区域2区域3区域4区域4-1区域4-2区域4-3区域4-4 区域5区域6 后处理工程下载 效果展示 所需素材 除了剑的模型外,主要是这五张贴图,其中swordmask和swordmask1中白色的区域是剑身的位置,sword…

Visual Studio2022实用使用技巧集

前言 对于.NET开发者而言Visual Studio是我们日常工作中比较常用的开发工具,掌握一些Visual Studio实用的搜索、查找、替换技巧可以帮助我们大大提高工作效率从而避免996。 Visual Studio更多实用技巧 https://github.com/YSGStudyHards/DotNetGuide 代码和功能搜…

上门回收小程序,打造回收新模式

近年来,我国一直秉持着环保绿色的发展理念,为了减少资源浪费,旧物回收成为了人们处理废弃物品的方式。目前,我国回收市场规模大约能达到3.58亿元,在我国经济的稳定增长和环保意识的提高下,回收市场规模还将…

【Java】--网络编程:基于TCP协议的网络通信

【Java】–网络编程:基于TCP协议的网络通信 文章目录 【Java】--网络编程:基于TCP协议的网络通信一、TCP协议1.1 概念1.2 三次握手1.2.1 文字描述1.2.2 画图演示 1.3 四次挥手1.3.1 文字描述1.3.2 画图演示 二、基于TCP的Socket网络编程2.1 概念2.2 服务…

Android 通过adb命令查看应用流量

一. 获取应用pid号 通过adb shell ps -A | grep 包名 来获取app的 pid号 二. 查看应用流量情况 使用adb shell cat /proc/#pid#/net/dev 命令 来获取流量数据 备注: Recevice: 表示收包 Transmit: 表示发包 bytes: 表示收发的字节数 packets: 表示收发正确的…