使用 Vespa 从 Python 构建新闻推荐应用程序
第 2 部分—从新闻搜索到嵌入的新闻推荐
在这一部分中,我们将开始使用本教程中创建的嵌入,将我们的应用程序从新闻搜索转换为新闻推荐。嵌入向量将代表每个用户和新闻文章。我们将提供用于下载的嵌入,以便更容易理解这篇文章。当用户来时,我们检索他的嵌入,并通过近似最近邻(ANN)搜索使用它来检索最近的新闻文章。我们还表明,Vespa 可以联合应用一般过滤和人工神经网络搜索,而不像市场上的竞争对手。
马特·波波维奇在 Unsplash 上拍摄的照片
我们假设你已经阅读了新闻搜索教程。因此,您应该有一个保存新闻搜索应用程序定义的app_package
变量和一个名为news
的 Docker 容器来运行一个搜索应用程序,该应用程序从 MIND 数据集的演示版本中获取新闻文章。
添加用户模式
我们需要添加另一种文档类型来表示用户。我们设置模式来搜索一个user_id
,并检索用户的嵌入向量。
我们通过指定fast-search
属性为属性字段user_id
构建一个索引。请记住,属性字段保存在内存中,默认情况下不进行索引。
嵌入场是张量场。Vespa 中的张量是灵活的多维数据结构,作为一等公民,可用于查询、文档字段和排名中的常数。张量可以是稠密的,也可以是稀疏的,或者两者兼有,并且可以包含任意数量的维度。更多信息请参见张量用户指南。这里我们定义了一个单维的稠密张量(d0
-维 0),代表一个向量。51 是本文中使用的嵌入大小。
我们现在有一个用于news
的模式和一个用于user
的模式。
['news', 'user']
索引新闻嵌入
类似于用户模式,我们将使用密集张量来表示新闻嵌入。但与用户嵌入字段不同,我们将通过在indexing
参数中包含index
来索引新闻嵌入,并指定我们希望使用 HNSW(分层可导航小世界)算法来构建索引。使用的距离度量是欧几里德。阅读这篇博文了解更多关于 Vespa 实现 ANN 搜索的历程。
使用嵌入的推荐
在这里,我们添加了一个使用紧密度排名特性的排名表达式,它计算欧几里德距离并使用它来对新闻文章进行排名。这个等级配置文件依赖于使用最近邻搜索操作符,我们将在搜索时回到下面。但是现在,这需要查询中的一个张量作为初始搜索点。
查询配置文件类型
上面的推荐等级配置文件要求我们随查询一起发送一个张量。为了让 Vespa 绑定正确的类型,它需要知道这个查询参数的预期类型。
当查询参数 ranking . features . query(user _ embedding)被传递时,该查询配置文件类型指示 Vespa 预期一个维数为d0[51]
的浮点张量。我们将在下面看到它是如何与最近邻搜索操作符一起工作的。
重新部署应用程序
我们做了所有必要的改变,将我们的新闻搜索应用变成了新闻推荐应用。我们现在可以将app_package
重新部署到名为news
的运行容器中。
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Finished deployment.
["Uploading application '/app/application' using http://localhost:19071/application/v2/tenant/default/session",
"Session 7 for tenant 'default' created.",
'Preparing session 7 using http://localhost:19071/application/v2/tenant/default/session/7/prepared',
"WARNING: Host named 'news' may not receive any config since it is not a canonical hostname. Disregard this warning when testing in a Docker container.",
"Session 7 for tenant 'default' prepared.",
'Activating session 7 using http://localhost:19071/application/v2/tenant/default/session/7/active',
"Session 7 for tenant 'default' activated.",
'Checksum: 62d964000c4ff4a5280b342cd8d95c80',
'Timestamp: 1616671116728',
'Generation: 7',
'']
喂养和部分更新:新闻和用户嵌入
为了让本教程易于理解,我们提供了已解析的嵌入供下载。要自己构建它们,请遵循本教程。
我们刚刚创建了user
模式,所以我们需要第一次输入用户数据。
对于新闻文档,我们只需要更新添加到news
模式中的embedding
字段。
获取用户嵌入
接下来,我们创建一个query_user_embedding
函数,通过user_id
检索用户embedding
。当然,您可以使用 Vespa 搜索器更有效地做到这一点,如这里描述的,但是在这一点上保持 python 中的所有内容会使学习更容易。
该函数将查询 Vespa,检索嵌入内容,并将其解析为一个浮点列表。下面是用户U63195
嵌入的前五个元素。
[0.0,
-0.1694680005311966,
-0.0703359991312027,
-0.03539799898862839,
0.14579899609088898]
获取推荐
人工神经网络搜索
下面的yql
指示 Vespa 从最接近用户嵌入的十个新闻文档中选择title
和category
。
我们还指定,我们希望通过我们之前定义的recommendation
rank-profile 对这些文档进行排序,并通过我们在app_package
中定义的查询配置文件类型ranking.features.query(user_embedding)
向用户发送嵌入。
这是十个回复中的前两个。
[{'id': 'index:news_content/0/aca03f4ba2274dd95b58db9a',
'relevance': 0.1460561756063909,
'source': 'news_content',
'fields': {'category': 'music',
'title': 'Broadway Star Laurel Griggs Suffered Asthma Attack Before She Died at Age 13'}},
{'id': 'index:news_content/0/bd02238644c604f3a2d53364',
'relevance': 0.14591827245062294,
'source': 'news_content',
'fields': {'category': 'tv',
'title': "Rip Taylor's Cause of Death Revealed, Memorial Service Scheduled for Later This Month"}}]
将人工神经网络搜索与查询过滤器相结合
Vespa ANN 搜索完全集成到 Vespa 查询树中。这种集成意味着我们可以包含查询过滤器,人工神经网络搜索将只应用于满足过滤器的文档。无需进行涉及过滤器的预处理或后处理。
以下yql
搜索以sports
为类别的新闻文档。
这是十个回复中的前两个。注意category
字段。
[{'id': 'index:news_content/0/375ea340c21b3138fae1a05c',
'relevance': 0.14417346200569972,
'source': 'news_content',
'fields': {'category': 'sports',
'title': 'Charles Rogers, former Michigan State football, Detroit Lions star, dead at 38'}},
{'id': 'index:news_content/0/2b892989020ddf7796dae435',
'relevance': 0.14404365847394848,
'source': 'news_content',
'fields': {'category': 'sports',
'title': "'Monday Night Football' commentator under fire after belittling criticism of 49ers kicker for missed field goal"}}]
结论和未来工作
我们通过在 Vespa 中存储用户资料,将我们的新闻搜索应用程序转变为新闻推荐应用程序。在这种情况下,用户简档被选择为由基于关于用户浏览历史的数据训练的 ML 模型生成的嵌入。然后,我们使用这些用户资料,根据近似最近邻搜索推荐新闻文章。未来的工作将集中在评估新闻推荐应用程序获得的结果是否符合用于生成嵌入的 ML 模型的预期。
使用机器学习构建抄袭检查器
Python、Flask、NLP、相似性搜索等等
克里斯多夫·伯恩斯在 Unsplash 上拍摄的照片
网络上、课堂上抄袭现象猖獗。有这么多的内容,有时很难知道什么时候被剽窃了。撰写博客文章的作者可能想要检查是否有人窃取了他们的作品并将其发布到其他地方。老师们可能想对照其他学术文章检查学生的论文是否抄袭。新闻媒体可能想要检查内容农场是否窃取了他们的新闻文章并声称内容是自己的。
那么,我们如何防范抄袭呢?如果我们能让软件为我们做这些繁重的工作,那不是很好吗?使用机器学习,我们可以构建自己的剽窃检查器,在庞大的数据库中搜索被盗内容。在本文中,我们将做到这一点。
我们将构建一个 Python Flask 应用程序,它使用松果——一个相似性搜索服务——来查找可能抄袭的内容。
演示应用概述
让我们来看看我们今天要构建的演示应用程序。下面,你可以看到一个应用程序运行的简短动画。
UI 提供了一个简单的 textarea 输入,用户可以在其中粘贴文章中的文本。当用户点击提交按钮时,该输入用于查询文章数据库。然后向用户显示结果及其匹配分数。为了帮助减少噪音,该应用程序还包括一个滑块输入,用户可以在其中指定一个相似性阈值,以便只显示非常强的匹配。
演示应用——剽窃检查器
正如你所看到的,当原始内容被用作搜索输入时,可能抄袭的文章的匹配分数相对较低。然而,如果我们从数据库中的一篇文章中复制并粘贴文本,抄袭文章的结果会有 99.99%的匹配!
那么,我们是怎么做到的呢?
在构建应用程序时,我们从 Kaggle 的新闻文章数据集开始。该数据集包含来自 15 个主要出版物的 143,000 篇新闻文章,但我们只使用了前 20,000 篇。(这个数据库的完整数据集包含超过 200 万篇文章!)
接下来,我们通过重命名几列并删除一些不必要的列来清理数据集。然后,我们通过嵌入模型运行文章,以创建向量嵌入——这是机器学习算法的元数据,用于确定各种输入之间的相似性。我们使用平均单词嵌入模型。最后,我们将这些矢量嵌入插入到由松果管理的矢量数据库中。
将矢量嵌入添加到数据库并建立索引后,我们就可以开始寻找相似的内容了。当用户提交他们的文章文本作为输入时,会向一个 API 端点发出请求,该端点使用 Pinecone 的 SDK 来查询矢量嵌入的索引。端点返回 10 篇可能抄袭的类似文章,并在应用程序的 UI 中显示出来。就是这样!很简单,对吧?
如果你想自己尝试一下,你可以在 GitHub 上找到这个应用的代码。README
包含如何在您自己的机器上本地运行应用程序的说明。
演示应用程序代码演练
我们已经了解了应用程序的内部工作原理,但是我们实际上是如何构建它的呢?如前所述,这是一个利用松果 SDK 的 Python Flask 应用程序。HTML 使用模板文件,前端的其余部分使用静态 CSS 和 JS 资产构建。为了简单起见,所有的后端代码都在app.py
文件中,我们在下面完整地复制了它:
让我们检查一下app.py
文件的重要部分,以便理解它。
在第 1–14 行,我们导入了应用程序的依赖项。我们的应用依赖于以下内容:
dotenv
用于从.env
文件中读取环境变量flask
用于网络应用程序设置json
用于使用 JSONos
也用于获取环境变量pandas
用于处理数据集pinecone
使用松果 SDKre
用于处理正则表达式(RegEx)requests
请求 API 下载我们的数据集statistics
获取一些方便的统计方法sentence_transformers
对于我们的嵌入模型swifter
用于处理熊猫数据框
在第 16 行,我们提供了一些样板代码来告诉 Flask 我们的应用程序的名称。
在第 18–20 行,我们定义了一些将在应用程序中使用的常量。其中包括松果索引的名称、数据集的文件名以及从 CSV 文件中读取的行数。
在第 22–25 行,我们的initialize_pinecone
方法从.env
文件中获取我们的 API 密匙,并用它来初始化松果。
在第 27–29 行,我们的delete_existing_pinecone_index
方法在松果实例中搜索与我们正在使用的名称相同的索引(“剽窃检查器”)。如果找到一个现有的索引,我们就删除它。
在第 31–35 行,我们的create_pinecone_index
方法使用我们选择的名称(“剽窃检查器”)、“余弦”邻近度度量和一个碎片创建了一个新的索引。
在第 37–40 行,我们的create_model
方法使用sentence_transformers
库来处理平均单词嵌入模型。稍后我们将使用这个模型对矢量嵌入进行编码。
在第 62–68 行,我们的process_file
方法读取 CSV 文件,然后对其调用prepare_data
和upload_items
方法。接下来描述这两种方法。
在第 42–56 行,我们的prepare_data
方法通过重命名第一个“id”列并删除“date”列来调整数据集。然后,它将文章标题和文章内容组合成一个字段。我们将在创建矢量嵌入时使用这个组合字段。
在第 58–60 行,我们的upload_items
方法通过使用我们的模型对文章进行编码,为每篇文章创建一个矢量嵌入。然后,我们将矢量嵌入插入到松果索引中。
在第 70–74 行,我们的map_titles
和map_publications
方法创建了一些标题和出版物名称的字典,以便以后更容易通过它们的 id 找到文章。
到目前为止,当后端应用程序启动时,我们描述的每个方法都在第 95–101 行被调用。这项工作为我们基于用户输入实际查询松果索引的最后一步做准备。
在第 103–113 行,我们为我们的应用程序定义了两条路径:一条到主页,一条到 API 端点。主页提供了index.html
模板文件以及 JS 和 CSS 资产,API 端点提供了查询松果索引的搜索功能。
最后,在第 76–93 行,我们的query_pinecone
方法获取用户的文章内容输入,将其转换为矢量嵌入,然后查询松果索引来查找相似的文章。当点击/api/search
端点时调用该方法,这发生在用户提交新的搜索查询的任何时候。
对于视觉学习者来说,这里有一个图表概述了该应用程序的工作原理:
应用架构和用户体验
示例场景
那么,把这些放在一起,用户体验是什么样的呢?让我们来看三个场景:原创内容、抄袭内容的精确副本和“补丁编写”的内容。
当提交原创内容时,应用程序会回复一些可能相关的文章,但匹配度很低。这是一个好迹象,因为内容没有抄袭,所以我们会期待低匹配分数。
当提交抄袭内容的精确副本时,应用程序会对一篇文章给出近乎完美的匹配分数。那是因为内容一模一样。不错的发现,抄袭检查!
现在,对于第三个场景,我们应该定义“补丁编写的”内容的含义。补丁写作是剽窃的一种形式,在这种形式中,有人复制并粘贴窃取的内容,然后试图通过更改一些文字来掩盖他们剽窃作品的事实。如果原始文章中的一句话是,“他为找到他丢失的狗而欣喜若狂”,有人可能会将内容改为“他很高兴找回他丢失的狗。”这与转述有些不同,因为在整篇抄袭的文章中,内容的主要句子结构通常保持不变。
有趣的是:我们的剽窃检查器在识别“补丁编写”内容方面也做得很好!如果您复制并粘贴数据库中的一篇文章,然后在这里或那里更改一些单词,甚至可能删除几个句子或段落,匹配分数仍然会以近乎完美的匹配返回!当我用一篇匹配率为 99.99%的复制粘贴的文章尝试这样做时,在我修改之后,“编写的补丁”内容仍然返回 99.88%的匹配率!
不算太寒酸!我们的剽窃检查器看起来运行良好。
结论和下一步措施
我们现在已经创建了一个简单的 Python 应用程序来解决现实世界中的问题。模仿可能是奉承的最高形式,但没有人喜欢自己的作品被偷。在一个不断增长的内容世界中,像这样的剽窃检查器对作者和老师都非常有用。
这个演示应用程序确实有一些限制,因为它毕竟只是一个演示。加载到我们索引中的文章数据库仅包含来自 15 个主要新闻出版物的 20,000 篇文章。然而,有数百万甚至数十亿的文章和博客文章。像这样的剽窃检查器只有在检查你的输入和所有你的作品可能被剽窃的地方时才有用。如果我们的索引中有更多的文章,如果我们不断地添加到它,这个应用程序会更好。
无论如何,在这一点上,我们已经展示了一个坚实的概念证明。松果作为一个管理相似性搜索服务,在机器学习方面为我们做了大量工作。有了它,我们能够相当容易地构建一个利用自然语言处理和语义搜索的有用应用程序,现在我们可以安心地知道我们的工作没有被剽窃。
利用 K-最近邻算法构建板球运动员推荐系统
使用 k-最近邻算法构建简单推荐系统的初学者指南。
在本文中,我们将构建一个简单的板球运动员推荐系统,该系统将根据过去为该队打球的运动员的统计数据,为该队推荐击球手名单。
我们将只为击球手构建推荐系统,通过计算他们各自的指标,该系统可以扩展到投球手和其他类型的球员。
k 近邻概述
简而言之,k-nearest neighbors (kNN)算法根据任何距离度量找出距离数据点最近的 k 个邻居。在计算数据点相似性的方式上,它与 k-means 非常相似。我们将使用 kNN 算法来推荐最接近当前团队成员的玩家。
数据采集
用于该系统的数据集是从 Kaggle 上的印度超级联赛 CSV 数据集下载的。它由 6 个 CSV 文件组成,总结了截至 IPL 第 9 赛季的 577 场 IPL 比赛的逐球信息。
理解数据
我们将使用 Pandas 来读取以下 CSV 文件。
- Ball_by_Ball.csv — 这个文件有比赛中每一个球的数据。我们可以提取前锋和非前锋球员的身份,得分等等。我们将使用这个文件来计算推荐系统的击球手统计数据。
- Match.csv — 该文件存储关于比赛的信息,如场地、球队、结果、裁判的详细信息等。我们将需要这个文件来提取一个
Match_Id
和Season_Id
之间的关联。 - Player.csv — 该文件包含所有球员的数据,即他们的姓名、国家、出生日期等。这些字段将用于使用 k-最近邻算法构建我们的推荐系统。
- Player_Match.csv — 该文件将
Player_Id
与他们参加过的比赛相关联。我们会用这个文件来了解当前队伍中球员的特点。
数据清理
我们将创建另一个名为player_data
的数据帧来存储击球手统计数据和来自现有player
数据帧的其他相关特征。由于player
数据帧有两列Is_Umpire
和unnamed:7
,这对我们的用例来说无关紧要,我们将删除它们并将其他列复制到player_data
。
player_data = player.drop(["Is_Umpire", "Unnamed: 7"], axis = 1)
特征抽出
从 Match_Id 导出赛季
我们将得出每个赛季球员的表现统计。match
数据帧具有字段Match_Id
和Season_Id
,可用于从Match_Id
中导出季节编号。
NUMBER_OF_SEASONS = 9
season_info = pd.DataFrame(columns = ['Season', 'Match_Id_start', 'Match_Id_end'])for season in range(1, NUMBER_OF_SEASONS + 1):
match_info = match.loc[match['Season_Id'] == season]['Match_Id']
season_info = season_info.append({
'Season' : season,
'Match_Id_start' : match_info.min(),
'Match_Id_end' : match_info.max()
}, ignore_index=True)
上面的代码片段会找到每个季节的Match_Id
的范围。
每个赛季的 Match_Id 范围
基于以上结果,我们将创建一个函数,该函数将基于比赛的 id 返回正确的赛季号。
def get_season_from_match_id(match_id):
season = season_info.loc[
(season_info['Match_Id_start'] <= match_id) &
(season_info['Match_Id_end'] >= match_id)] ['Season']
# Return the integer value of the season else return -1 if
season is not found
return season.item() if not season.empty else -1
每个赛季击球成绩的计算
根据ball_by_ball
数据,我们将计算每个赛季所有球员的以下特征:
- 得分得分
- 玩的局数
- 玩家没有出局的局数
- 面对球
- 四的数量
- 六的数量
计算得分、面对的球数、4 分和 6 分的数量非常简单。在ball_by_ball
数据框中,我们可以简单地检查Striker_Id
和Batsman_Scored
列中的值,并相应地增加这些特征。
难点在于计算每个赛季打的局数和球员没有出局的局数。为此,我们不仅需要查看数据帧中的当前行,还需要查看前一行。在下列情况下,玩家的局数应该增加:
Match_Id
前一个球与当前球不同。这意味着当前行属于新的比赛,因此新的一局将开始。我们将增加射手和非射手的局数。Match_Id
与前一个和当前焊球相同,但Innings_Id
发生变化。这意味着这是同一场比赛的第二局。我们将增加射手和非射手的局数。- 前一个球和当前球中的
Match_Id
和Innings_Id
相同,但当前的Striker_Id
不等于前一个Striker_Id
或Non_Striker_Id
。这意味着有新的玩家来击球了,所以我们将只为 id 等于Striker_Id
的玩家增加局数。类似的逻辑也适用于电流Non_Striker_Id.
我们还将跟踪Player_dismissed
列,找出玩家是否在特定的一局中没有出局。
击球统计的计算
最后一步是计算击球统计数据,如击球命中率(BSR) 、击球率(BA) 和每局边界得分(BRPI) 。首先每个赛季计算 BSR、BA 和 BRPI,然后根据球员参加的赛季数计算这些值的平均值。在计算平均指标时,只考虑击球手实际打过的那些赛季。这消除了对过去所有赛季都参加过比赛的球员的偏见。
每个赛季平均击球率的计算
每季击球命中率的计算
每个赛季每局边界得分的计算
一旦我们计算了这些统计数据,我们还可以得出球员的年龄,以及他们是国内还是国际球员。这些属性很重要,因为假设目前超过 40 岁的球员不会参加下个赛季的比赛。此外,由于在 IPL 球队中选择国际球员的限制,国内球员的属性将很重要。
K-最近邻的实现
对于 k-最近邻的实现,我们将使用 scikit learn 并构建一个 numpy 数组,其中只有那些特征有助于团队选择,即 BA、BSR、BRPI、年龄和国籍。
x 是代表这些特征的 numpy 数组。
from sklearn.neighbors import NearestNeighborsnbrs = NearestNeighbors(n_neighbors=3, algorithm='ball_tree').fit(X)
distances, indices = nbrs.kneighbors(X)
indices
将给出 x 中每一行的最近邻的索引
前几个玩家和他们最近的邻居的可视化。节点号是玩家的 id
对于在当前赛季中在特定球队中比赛的所有球员,kNN 将返回与现有球员相似的 3 个最近邻居。
在建议的 3 个玩家中,第一个玩家将与现有玩家相同,因为玩家与自己的距离为 0。
所有推荐的玩家都被添加到有序集合中,并按照最高 BSR 到最低排序。我们可以编程返回前 n 个击球手,其中 n 可以根据需要更改。
最终输出推荐 15 名球员按击球命中率排序。
这是击球手推荐系统的一个非常简单的实现。你可以在这里查看代码的 GitHub 库。感谢您的阅读!😃
编写生产就绪 API -第 1 部分:实现 ORM
为我们的网站创建一个高效、安全和快速的 API,而不需要编写一行 SQL
我们的 API 会比这些可爱的生物更快(图片由切瓦农摄影在像素上拍摄)
想象一下去一家餐馆。你坐下来,看菜单,选择一些菜。然后你走向厨房,告诉厨师你想吃什么,等他吃完后再把你的饭菜端上桌。这家奇怪的餐馆里发生了什么事?
没有 API 的应用程序就像没有服务员的餐馆。在餐馆里,你不需要和厨房沟通,也不需要等着点菜来享用美食。同样的,一个网站不需要知道如何与你的数据库通信。像一个服务员一样,我们的 API 从我们的网站收到一个命令:“我想要一些带有元数据的用户统计数据”。API 随后检查订单(是否允许您拥有该数据?),说服我们的数据库(厨师)为他烹制一些美味的信息,等待数据库完成,最后将数据返回到网站。
这篇文章是关于什么的?
我们将使用 ORM 为我们正在构建的名为 BeerSnob 的现实世界应用程序创建一个全功能、快速和安全的 API 一个专门为喝优质啤酒的人建立的网站。它允许用户分享关于他们在特定场所喝的啤酒的评论;在提供价格和口味信息的同时,对场地和啤酒进行评级。在本文结束时,您将拥有一个带有 ORM 的工作 API,并有一个迁移模型来完成它!首先我们进入为什么我们会创建一个 API 或者 ORM,然后我们开始编码。
0.目标和准备
我们的目标是为 BeerSnob 创建一个 API,它将从网站接收用户创建的数据包。基于所需的动作,它然后从数据库中检索数据或将数据包插入到数据库中。数据包可能包含多个表的信息,API 的工作是确保正确的信息出现在正确的表中。
为什么要构建 API?
如果你点击脸书网站或应用程序中的“我的朋友”,你会向 API 发送信息请求。这个软件翻译你的请求,检查你是否被允许提出请求,收集所有的数据并用你的数据包回应。这很好,有几个原因:
- 保持我们的代码整洁
- 保护对我们数据库的访问(网站与我们的数据库分离,例如:我们的网站不需要有数据库凭证)
- 检查用户对数据的访问(我只能更改我的个人资料,不能更改其他人的)
为什么要使用 ORM?
ORM 代表对象关系映射,它是一种允许你使用对象从数据库中查询和操作数据的技术。您不必再编写查询,您可以使用对象来检索数据。伪代码示例:song_list = SongTable.query(artist="Snoop dogg")
。优点:
- 没必要写 SQL
- 很多事情都是自动完成的
- 阻止 SQL 注入
我们来编码吧!
1.设置
在 API 能够处理数据库数据之前,我们需要一个实际使用的数据库。在 这篇文章 中,我们使用迁移来创建所有的表、关联、关联和索引。无论您是否使用迁移,本文还包含一个非常漂亮的 BeerSnob 数据库结构图。
我们将在 本文 中构建的迁移模型上构建 API。如果你想编码,那么 git 从这里的https://github.com/mike-huls/beersnobv2****克隆代码。首先让我们构建一个 ORM,然后实现我们的 API。
2.为我们的 ORM 创建模型
ORM 是我们可以在 API 中使用的对象和数据库中的数据之间的转换。为了将数据库数据转换成对象,它使用“模型”。在我们的 BeerSnob 示例中,我们希望按照foundbeers = BeerTable.Get(ID=2)
的思路做一些事情。在这个例子中,BeerTable 是一个模型,它能够连接到数据库中的 Beers 表,并对其执行操作,如检索数据和插入新记录。
像这个好孩子一样,我们的 ORM 将在我们的努力中帮助我们
让我们创建我们的第一个模型;国家。这个模型处理我们国家表中的数据。在“models”目录下创建一个名为 countries.js 的新文件,内容如下:
这个简单的文件允许我们创建一个模型。创建一个模型并理解它是如何工作的并不难。重要的事情定义如下。
- 在 tableModel(第 5 行)中,我们添加了 modelName。我决定保持表名的复数形式(countries 表包含许多国家的记录)和模型名的单数形式(一个模型只描述一个国家)。
- 模型与另一个模型相关联(第 11 行)。我们告诉我们的 ORM,如果我们删除一个国家,一个城市应该被删除。我们还在国家表(CountryId)上定义了外键。
- 在 Init 中,我们定义了一些关于列的信息。ORM 需要知道数据库中列的数据类型和名称。
- 时间戳:false(第 24 行)。如果设置为 true,ORM 会添加额外的列来跟踪创建和修改的时间戳(我们手动处理这些,但是 ORM 也可以为您完成)。
当定义模型之间的关联时,有几个选项。到目前为止,我已经在这个项目中使用了一些,但是我们将在下一部分中更深入地研究它们。我还为其他表格创建了模型。查看存储库以获取更多信息。
3.原料药制备
在我们开始创建 API 之前,我们需要安装一些依赖项并准备一些东西。
3.1 安装包。
转到您的根文件夹并:
npm install --save express body-parser
npm install --save-dev nodemon
这将安装我们的 API 需要的包。Express 是一个 web 服务器,body-parser 允许我们解析通过该 web 服务器发送的请求体。然后我们安装一个开发依赖;这些仅用于构建我们的应用程序,并且通常仅用于开发。每次我们更改代码时,Nodemon 都会重新加载我们的 web 服务器。我的 f5 键对此非常感谢。
3.2 配置您的应用程序以使用 Nodemon
打开根文件夹中的 package.json 文件。调整“脚本”部分以反映以下内容:
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
},
这将允许我们在生产环境中调用npm run start
或npm run dev
用 nodemon 运行我们的应用程序,允许重启。
3.3 创建文件夹
在根目录下创建两个文件夹:“routes”和“service”。
4.构建 API
是时候让这些模型发挥作用了!有了 API,我们将能够接收请求并使用模型从数据库中检索数据。我们首先设计我们的服务器,它将捕获所有的请求,并将它们传递给一个路由。然后,路由将检查请求并与数据库通信。
该去拿东西了!(图片由 Pexels 上的约瑟夫·费尔拍摄)
4.1 为我们的应用程序创建服务器
使用下面的脚本,我们将有一个服务器启动并运行。
事情是这样的:
- 我们导入了一些包和日志服务。这个服务帮助我们调试,我们在第 13 行这样做。
- 在第 9 行,我们创建了一个可以传递请求的应用程序。
- 第 24 行;我们告诉 app 我们要用 bodyParser 通过这种方式,我们可以接收例如 json 数据。
- 第 29 行:我们设置 API 的规则。
- 第 41 行到第 46 行:我们捕获一些 URL 路径,并将它们传递给我们的 routes。
- 第 59 行:为我们的应用程序创建一个服务器,并告诉它监听本地主机上的端口 5000
4.2 创建路线和处理请求
现在我们的服务器已经启动并运行了,是时候将请求传递给我们在第 41 行到第 46 行定义的路由了。下面我将展示一个处理路由的例子。我已经以完全相同的方式实现了其他路线;你可以在找到我们的知识库。
在上面的代码中,您可以看到 ORM 在处理路由时是如何工作的。让我们走完第一条路线(11 号线至 39 号线)。
- 第 11 行:我们定义路线。
/search
在我们的例子中是指localhost:5000/api/beers/search
- 第 14 行:我们从 url 获取数据。req.query 检索 url 参数(T2 中的粗体部分)。我们将参数 q 的值存储在一个变量中,这个变量也称为 q(用于查询)。在 url
localhost:5000/api/beers/search?q=ale
中,键 q 的值是‘ale’。 - 第 20 行:如果 q 太短,什么也不做
- 第 23 行到第 30 行:返回所有包含 q 的啤酒(不区分大小写)
- 第 33 行 res.retun 是我们的 API 返回的内容。它将返回一个只有一个键的对象:“beers”和我们在数据库中找到的所有啤酒的数组。我们返回状态代码 200(成功)。
- 第 36 行:如果 try-block 中有任何错误,我们通过返回一个错误让客户端知道(我们使用 errorService 来完成这个任务)。
如您所见,我们不必自己编写一行 SQL 我们可以调用模型来翻译我们的请求并与我们的数据库通信。这不仅很方便,还能防止 SQL 注入。
5.测试我们的路线
让我们测试我们的啤酒路线!在啤酒行业,有三条不同的道路:
- 这条路线使用我们的 ORM 来查询 Beers 表。你可以通过一个搜索词(q)像
localhost:5000/api/beers/search?q=heine
。然后它会寻找类似 q 的啤酒。 - 一个 GET for /
这个路由使用可选的查询参数 Id,如果提供了 Id,就尝试查找记录。否则它返回所有啤酒。尝试localhost:5000/api/beers
或localhost:5000/api/beers?id=1
- 一个用于/
的 POST 此路由接受一个它将在第 72 行(req.body)上捕获的主体。试着将下面的 json 发布到localhost:5000/api/beers
,你会看到数据库中出现一条新记录。
{
"Name": "Bud Light",
"Type": "Beer flavored water"
}
这是一篇相当长的文章:这只可爱的小狗是我们应得的(图片由 Hannah Grace 在 Unsplash 上提供)
结论
这个 API 为我们的应用程序提供了一些不错的基本功能!使用我们的 ORM,我们现在能够使用我们的 API 来搜索、获取和创建国家、城市、地点、啤酒、用户和报告。在下一部分中,我们将进一步充实我们的 API:
- 我们将添加更深入的关联(返回用户 X 提交的所有啤酒或返回访问过场所 X 并报告了啤酒 Y 的所有用户)。
- 实现更多的功能,例如:用户想要更新他们的密码
- 我们会增加安全措施。我只能编辑自己的密码,不能编辑别人的。
这是一篇很长的文章;我希望你到这里为止,我的解释够清楚了。如果不是,请让我知道我可以在哪里提高自己。关注我敬请关注!
—迈克
使用电报机器人创建一个货物跟踪工具
设计一个电报机器人,它将与卡车司机互动,以跟踪您的货物,并提供您的运输性能的实时可见性
零售商和快速消费品公司正面临着越来越大的压力,以改善他们的供应链,增加他们的灵活性和降低成本。
使用配送中心(DC) 是一个有效的解决方案,因为它们允许在一个地方储存来自靠近最终客户的不同供应商的各种产品。
然而,它应该与有效的发货跟踪相结合,以便为商店提供准确的 eta,确保交付流程的透明度并衡量绩效。
💌新文章直接免费放入您的收件箱:时事通讯
一、TMS &跟踪工具的局限性
例子
你是一家中型零售商,在运输行业不成熟的市场上经营。
您希望实施由外部提供商提议的运输管理系统(TMS) ,以获得对您的货件的全面可见性和实时跟踪。
你能面对什么样的障碍?
- **系统接口:**您有多个不同系统的运营商
- **运营商成熟度:**他们用手工流程(Excel)管理他们的车队
- **当地具体情况:承运人不经营自己的车队(分包)
- **谈判能力有限:**因为与其他客户相比,您的业务量较低,承运商拒绝调整他们的流程,也不使用您的系统来记录状态
如果您正面临这些障碍,本文中介绍的解决方案可能会满足您的需求。
二。我们需要什么?
一个简单、便宜且易于实施的解决方案,用于跟踪您的货件
- 不需要为您的运营商进行额外的 IT 开发
- 轻松整合到当前的运输流程中
- 减少物流团队的管理工作量
- 不会影响驾驶员的工作效率
- 不需要额外设备
- 提供可见性、实时跟踪和透明度
电报机器人:您提升物流绩效的最佳盟友
三世。什么是电报机器人?
电报
Telegram 是一款安全、便捷的跨平台消息应用,这意味着它可以在您的所有设备上运行。Telegram 在全球拥有超过 5 亿用户,它有一个对所有人免费的开放 API 和协议。有了这个 API,我们可以构建自己的工具,包括机器人。
什么是机器人?
机器人是第三方应用程序,可以通过向用户发送消息、命令和内嵌请求来与用户进行交互。使用 Telegram,您可以通过向电报机器人 API 发送 HTTPS 请求来设计和控制电报机器人。
您的机器人可以发送/接收消息、照片、视频和 GPS 位置,足以构建我们的货件跟踪工具。
如何与电报机器人互动?
添加他并开始对话:)
四。创建你的追踪助手机器人
标准运营模式(SOP)
对于我们的 bot 的第一个版本,让我们用一个简单版本的 SOP 来记录交付时间。
确认在目的地卸货
- 商店团队已将您的货物从卡车上卸下
- 司机与你的电报机器人分享 货物编号、 GPS 位置 n 和货物的图片 以确认交货
- 电报机器人通过电子邮件发送一个 交货通知 给 你的物流团队 上面列出的信息
编辑:你可以在下面的链接中找到这篇文章的 Youtube 版本和动画。
动词 (verb 的缩写)演示:发货交付确认
方案
您的货物已在您的商店卸载。司机想在前往下一个目的地之前发送交货确认。
第一步:司机打开电报,开始与机器人讨论
驱动程序启动进程|机器人询问 GPS 位置—(图片由作者提供)
第二步:司机分享自己的 GPS 位置
司机分享其 GPS 位置| BOT 要求送货编号—(图片由作者提供)
第三步:司机分享一个送货号码
司机分享其发货编号| BOT 索要发货图片—(图片由作者提供)
第四步:司机分享货物的图片
司机分享发货照片| BOT 停止流程并发送电子邮件(图片由作者提供)
第五步:您的物流团队收到发货确认
BOT 通过邮件向运输团队发送交货确认(图片由作者提供)
七。设计你的电报机器人
1。用另一个机器人创建你的机器人:)
@ BotFather 是一个电报机器人,它将帮助你创建自己的机器人
- 在电报上搜索@ BotFather,并发送给他 ‘/start’
- 回答 ‘/newbot’ 消息,并按照说明设置一个名称和一个用户名
- 您的 bot 现在已经准备好了,创建了一个 API 令牌— 请保留这个令牌的副本!
用@ BotFather(图片由作者提供)通过三个步骤创建您的电报
2。安装 Python 包
包来管理你的电报机器人
pip install python-telegram-bot
3。导入库并启用日志记录
导入库并初始化你的电报机器人
TOKEN :创建你的 bot
APP _ NAME:你的 Heroku 应用的地址(见以下步骤)
4。带有对话处理程序的主函数
为了简化驱动程序的过程,您的 BOT 将使用 Telegram API 的 ConversationHandler 函数按顺序询问信息
由 Telegram API 的 ConversationHandler 函数处理的装运信息收集过程(图片由作者提供)
对话处理程序为具有取消功能的驱动程序创建一系列指令
照片示例 功能
- photo_file :提取用户写的消息中最后上传的照片
- 链接 1 :电报 API 创建的链接,我们可以从中提取照片文件 id
- link 2:Telegram API 创建的保存这张照片的网页
- 邮件功能:用 HTML 发送一封带有 delivery_number、gps_location 和内嵌照片的邮件
照片功能示例
关于 Telegram API 的更多细节,我强烈建议查看文章末尾的参考链接列表。
5.邮件功能
在收集了递送号码、GPS 位置和装运图片后,您的机器人将使用 smtplib python 包和 Gmail 帐户通过电子邮件向您的运输团队发送通知。
可以在脚本 mail.py 中找到 mail 函数。
6.在云上托管您的机器人
Heroku 是一个基于云的服务,在这里你可以托管你的网络应用;托管的免费公式提供了足够的资源来运行你的应用程序。
Procfile
requirements.txt
在 Heroku 上设置您的应用程序需要上面列出的两个文件。
在这篇由浩辉 ( 链接)撰写的好媒体文章中,你可以找到如何在 Heroku 上部署你的电报机器人的详细说明。
后续步骤
关注我的 medium,了解更多与供应链数据科学相关的见解。
这是一个非常简单的版本,展示了电报机器人的潜力。
我们可以通过增加
- 实时 GPS 位置跟踪
- 将记录存储在数据库/或/ google 工作表中
- 增加扫描功能(条码/二维码),避免司机手动输入发货编号
- 在延迟交付的情况下获取商店评论和司机评论的功能?
- 运输敏感货物时的封条管理
你对可以添加的功能有什么想法吗?
请掉个评论,让我们努力打造更好的版本!
关于我
让我们在 Linkedin 上连线,我是一名供应链工程师,正在使用数据分析来改善物流运营并降低成本。
如果你对数据分析和供应链感兴趣,可以看看我的网站
参考
为了简洁易读,本文跳过了许多细节。你可以在下面列出的优秀文章中找到详细的说明。
【1】—https://www.freecodecamp.org/news/learn-to-build-your-first-bot-in-telegram-with-python-4c99526765e4/Dzaky Widya、 用 Python 、freecodecamp.org学会在电报中构建你的第一个 bot
【2】—浩辉 、 如何免费部署一个使用 Heroku 的电报 Bot、中型
【3】—吴伟峰 、 如何用 Python 创建电报 Bot、中型
[4] — 电报 API 文档
用 Node,Express 和 MongoDB 构建一个 REST API
让我们使用 Node、Express 和 MongoDB 构建一个遵循 CRUD 原则的 REST API,并使用 Postman 测试它。
由 Unsplash 上 Greg Rakozy 拍摄的照片
API 现在是很常见的东西。它们在网站上随处可见。API 充当存储所有数据的数据库和用户与之交互以访问数据的前端之间的连接。
API 是指**应用编程接口,**是一套明确定义的前端和数据库之间的通信方法。
REST 代表代表性状态转移,是一种架构风格,用于在网络上的计算机系统之间提供标准,使系统之间更容易相互通信。
REST APIs 大多使用 JSON 作为传输数据的首选,因为它们易于理解和阅读。
在本教程中,我们将使用 Node、Express 和 MongoDB 来创建一个 REST API,它将支持四个操作— GET、POST、PUT 和 DELETE。
所以,我们先来讨论这四个操作,并试着理解它们在 API 开发的上下文中意味着什么。
- GET — GET 表示读取数据。该操作的功能是从数据库中检索数据并呈现给用户。
- POST — POST,顾名思义,用于向数据库发布/添加新数据。它允许用户向数据库添加新数据。
- 上传 —上传意味着更新数据库中已经存在的数据。
- 删除 —用于从数据库中删除任何现有数据。
因此,我们的 REST API 将执行所有这四个操作。我们将使用 Express package 来简化我们的工作。我们将使用 MongoDB 作为 NoSQL 数据库来存储我们所有的数据。MongoDB 以 JSON 格式存储数据。
所以,我们会一步一步来。首先,我们将构建 API 端点,然后我们将连接到数据库来执行实际操作。我们将使用 Postman 软件进行 API 测试。
设置项目
首先,我们需要在我们的系统上下载 Node。然后我们可以开始创建我们的项目。
因此,首先,我们需要在系统中创建一个文件夹,我们希望在其中构建我们的项目。我将文件夹的名称保留为 rest-API 。
然后我们需要移动到我们刚刚创建的 rest-API 文件夹中。现在开始一个新项目,我们将在文件夹中运行以下命令:-
npm init
它会询问有关项目的各种问题,如名称,描述和其他事情。我们希望除了名称和描述之外的所有内容都保持默认模式,我们可以在方便的时候添加名称和描述。
完成后,我们会在文件夹中看到一个 package.json 文件。它包含了我们刚刚给出的创建这个文件的所有数据。你可以看到入口点是 index.js 文件。
在创建了 package.json 文件之后,我们需要在我们的机器上下载 Express。要安装 Express,我们可以:-
npm install express --save
这将在我们的系统中下载并保存 express,并且将 express 作为一个依赖项添加到我们的 package.json 文件中。
我们还想下载一个名为 nodemon 的开发依赖项,这将允许我们更快地开发。这将有助于我们避免每次更改时重启服务器,并且会自动刷新,这将节省我们很多时间。
因此,要安装 *nodemon,*我们应该:
npm install --save-dev nodemon
注意,我们已经使用了 save-dev 来安装并将其添加到 package.json 文件中作为开发依赖项,因为我们使用它来加速我们的开发过程。
现在,我们需要将 MongoDB 下载到我们的系统中,然后创建集群并将其连接到您的本地计算机。
接下来,我们必须从我们的 express 应用程序下载mongose来与 MongoDB 数据库交互。
要安装猫鼬,请执行以下操作:
npm install mongoose --save
现在,我们准备开始构建我们的 REST API。在开始之前,我想展示一下我的 package.json 文件,这样你就可以验证一切进展顺利。
所以,让我们开始构建我们的 REST API。首先,我们需要创建一个名为 index.js 的文件;正如我们可以看到的,它是我们应用程序的入口点。
索引文件
我们将从 index.js 文件开始。我们将首先要求 express 进入我们的系统。
const express = require('express');
然后,我们将通过编写以下代码行来设置我们的 express 应用程序
const app = express();
因此,我们将设置一个 GET 函数来使用浏览器测试它。当我们向 localhost:4000/API 发出 GET 请求时,我们传递一条消息作为响应。
app.get('/api', (req, res) => res.send('Its working!'));
然后,我们将设置我们的应用程序开始监听请求。我们将使用 4000 作为端口号。我们在那里使用了 OR 操作符,这样如果有任何通过环境变量定义的端口号,它就可以使用它;不然就用 4000。您可以根据自己的选择选择端口号。我们将 console.log 一条消息来检查它是否正常工作。
app.listen(process.env.port || 4000, function(){
console.log('now listening for requests');
});
因此,当我们现在使用以下命令启动服务器时:
nodemon index
当我们转到 *localhost:4000/api,*时,我们会看到消息“*正在工作!”。*同样,在控制台中,我们会收到为控制台设置的消息。
现在,我们已经正确设置了 express 服务器,并且成功发送了第一个 GET 请求。
现在,我们希望将所有四个操作放在一个名为 api.js 的单独文件中,该文件位于 routes 文件夹下,因为我们希望避免将所有操作都放入 index.js 文件中。
因此,我们将删除这个 index.js 文件中的 app.get 部分。我们想在我们的文件中添加猫鼬作为需求。
const mongoose = require('mongoose');
接下来,在我们的 express 应用程序的设置下面,我们希望连接到 MongoDB。我们将使用以下代码来实现这一点:
mongoose.connect('mongodb://localhost/ourdata');
mongoose.Promise = global.Promise;
这里, ourdata 是我们将在本教程稍后在 MongoDb 中创建的模型的名称。
由于猫鼬.诺言现在贬值,我们也将猫鼬的诺言更新为全局诺言。
接下来,我们将在文件中添加一些中间件。我们将首先添加对静态文件的支持。虽然我们不会在本教程中提供静态文件,但拥有它是很好的,因为我们以后无论如何都需要添加一个前端来使用 API。
app.use(express.static('public'));
然后,我们将添加 Express 解析器来解析从数据库发送或接收的数据。
app.use(express.json());
然后,我们设置应用程序来使用新的 api.js 文件,我们将创建该文件来保存所有四个操作。
app.use('/api',require('./routes/api'));
我们在开头添加了 ‘/api’ ,以避免将其添加到所有四个操作中。
最后,我们添加了一个中间件来处理操作过程中出现的错误。
app.use(function(err,req,res,next){
res.status(422).send({error: err.message});
});
以下是 index.js 文件的最终代码
四个 CRUD 操作的布局
接下来,我们创建一个名为 router 的文件夹,并在该文件夹中创建一个名为 api.js 的新文件。这将包含我们想要用正在构建的 REST API 完成的所有四个 CRUD 操作。
我们首先在文件中要求 express。然后我们将使用快速路由器创建一个路由器。
const express = require('express');
const router = express.Router();
所以,让我们开始一个接一个地构建这四个操作。我们不会将任何东西保存到数据库中,因为我们还没有创建数据库,但是我们会更简单地测试它们。
因此,我们将从 GET 操作符开始。我们将以这种方式编写 GET 请求的代码:-
router.get('/students',function(req,res){
res.send({type: 'GET'});
};
这里,我们给出了一个端点和一个函数,该函数给出一个响应,该响应告诉我们发送的请求的类型。
接下来是 POST 请求。这将是一个类似的方式,虽然我们想返回的数据,我们收到的请求。
router.post('/students', function(req, res){
res.send({
type: 'POST',
name: req.body.name,
roll: req.body.roll
});
});
接下来是 PUT 和 DELETE 请求。现在,我们将返回两个操作的请求类型。它接受带有 id 的端点,这表示当我们保存数据到 MongoDB 时 MongoDB 提供的惟一 id。
router.put('/students/:id', function(req, res){
res.send({type: 'PUT'});
});
router.delete('/students/:id', function(req, res){
res.send({type: 'DELETE'});
});
接下来,我们将导出在 index.js 文件中使用的模块。
module.exports = router;
为了测试这些操作,我们将使用一个叫做 Postman 的软件。这很神奇,有助于快速测试 API。
下载 Postman 桌面代理或安装其 Chrome 扩展,开始使用 Postman。邮递员的新工作区如下所示
Postman API 测试
在这里,我们可以选择发送请求的操作类型和目标 URL。对于 POST 请求,我们需要在发送请求的同时发送一些 JSON 数据,这可以通过在 Body 部分添加 JSON 来实现。
您需要选择原始数据类型,然后选择 JSON 作为格式,如下所示:-
邮递员邮件请求
因此,我们可以很容易地通过 Postman 测试所有这些操作。当我们更新数据时,我们还需要在 PUT 请求时提供数据。我们只传递需要更新的数据。
构建数据库模式和模型
接下来,我们将创建一个名为 models 的文件夹,然后在该文件夹中创建一个 student.js 文件。
我们需要在那个文件夹中放入mongose,并构建一个模式,然后基于该模式构建一个模型。模式告诉模型如何构造数据。
我们正在建立一个模型,其中包含学生的数据——姓名、他们的点名号码以及他们是否在场。
- 名称 —这是字符串数据类型,在模式中不是必填字段。
- Roll —这也是字符串数据类型,是必填字段。它不能为空。
- 呈现 —这是一个布尔型字段,默认为真。
然后,在我们创建的学生模式的帮助下,我们创建了名为学生的模型。然后,我们导出模型以在 API 文件中使用它。
那么,让我们来看看 student.js 文件:-
最终确定 api.js 文件
现在,我们将通过从我们创建的数据库模型中保存和检索数据,使所有四个 API 端点都可用。
因此,我们需要在 API 文件中包含该数据库模型。
const Student = require('../models/student');
然后,我们从 GET 请求开始。我们会获取数据库中的所有学生,并作为响应发送给他们。您可以为学生添加任何类型的过滤,但是我们将 find 函数保留为空,以便从数据库中访问每个学生。然后我们使用*。catch(next)* 函数帮助捕捉任何错误,并将其传递给下一个中间件——在我们的例子中是错误处理中间件。
router.get('/students',function(req,res,next){
Student.find({}).then(function(students){
res.send(students);
}).catch(next);
});
接下来,我们要处理 POST 请求。我们在数据库中创建一个新学生,然后返回创建的学生作为响应。
router.post('/students',function(req,res,next){
Student.create(req.body).then(function(student){
res.send(student);
}).catch(next);
});
接下来,我们有 PUT 请求。我们将使用 findOneAndUpdate 函数,使用我们在 URL 端点中传递的 id 在数据库中查找相应的条目。然后,我们在 Id 的帮助下找到同一个学生,并返回更新后的学生作为响应。
router.put('/students/:id',function(req,res,next){
Student.findOneAndUpdate({_id: req.params.id},req.body).then(function(student){
Student.findOne({_id: req.params.id}).then(function(student){
res.send(student);
});
});
});
最后,我们有删除请求。我们使用函数 findOneAndDelete 通过提供的 id 在数据库中找到相应的学生,并从数据库中删除该学生。它还返回被删除的学生作为响应。
router.delete('/students/:id',function(req,res,next){
Student.findOneAndDelete({_id: req.params.id}).then(function(student){
res.send(student);
});
});
我们可以使用 Postman 软件非常容易地测试所有这些。在测试中,一切都应该很好,我们已经做得很好,很干净。
下面是 api.js 文件的最终代码:-
最后,我们创建了 REST API,它执行所有四个 CRUD 操作。因此,如你所见,在 Node、Express 和 MongoDB 的帮助下,构建 REST API 非常容易。
希望你觉得这个教程很有趣,并且学到了一些新东西。
这里还有一些值得一读的教程:
https://javascript.plainenglish.io/build-a-blog-app-with-react-intro-and-set-up-part-1-ddf5c674d25b https://shubhamstudent5.medium.com/build-an-e-commerce-website-with-mern-stack-part-1-setting-up-the-project-eecd710e2696 https://medium.com/javascript-in-plain-english/build-a-simple-todo-app-using-react-a492adc9c8a4
用 SQL 构建搜索引擎
使用全文搜索
在 Unsplash 上 Marten Newhall 拍摄的照片
如果您使用 SQL 来执行文本搜索,您可能会使用类似于的命令。但是 like 命令的限制是它寻找精确的匹配。幸运的是,SQL 提供了一个特性——SQL 全文索引——可以对任何包含原始文本的列进行模糊文本搜索。这是上帝为 NLP 项目派来的。
我是 python 提供的 NLP 库——scikit learn 和 spaCy 的忠实粉丝。
但是在进入文本处理的深水区之前,最好先尝试一下 SQL 的全文索引。
在本文中,我们将了解如何使用 MS SQL 的文本搜索功能来执行弹性搜索。是的,完全成熟的弹性搜索。
资料组
我们将使用亚马逊点评数据集,网址为:
让我们专注于一个产品类别
作者捕获的屏幕截图
把下载的 json 导入 python,看一下数据。
作者捕获的屏幕截图
将数据推入 SQL
作者捕获的屏幕截图
设置全文搜索功能
先做点家务。
在 SQL 中,检查 SQL Server 中是否安装了全文功能
如果尚未安装,请使用以下链接进行安装。
https://www.sqlshack.com/hands-full-text-search-sql-server/
检查它是否已启用。
在 AmazonReviews 表上创建全文目录。
可以把这里想象成索引将要被填充的地方…
人口…这是什么意思…?
我们很快就会知道…
现在,看看 AmazonReviews 表的主键。
嗯(表示踌躇等)…
该表将 ID 作为主键。
在索引中,它被命名为 PK_AmazonRe_3212…
为了方便以后访问,我们将其重命名。
表的主键
看上去好多了。
现在,我们一直在等待的部分…
填充,即填充全文索引。这使我们能够对评论文本执行超快速搜索。
让我们来看看全文的内容。
《金融时报》索引的内容
这就是我们所说的填充索引。
Its 有 121995 个条目。它记录了哪个术语在哪个列中出现了多少次。
就像我们在 scikit learn 中创建的计数矢量器中的词汇表一样。
最后,让对 reviewText 列执行搜索操作。
你瞧…!
精确匹配排名更高
28000 行匹配结果。
让我们进一步探索…
比赛的低端
排名较高的行包含与搜索词“低电量”完全匹配的内容。而相反,排名较低的行包含部分匹配,如仅单词“低”或仅单词“电池”。
此外,请注意,当我们滚动浏览结果时,评论的长度会增加。
排名是如何运作的?
在这一点上,理解行是如何排列的是很有趣的。
它的排名基于 OKAPI BM 公式。
完整的公式是:
但实际上归结为以下因素:
查询中的字数
数据库中匹配查询词的行数
以 DB 为单位的行的平均长度
词的频率(DB)
查询中的词频
这解释了为什么具有 12330 个字符的匹配行具有最低的等级分数,而具有 141 个字符的匹配行具有最高的等级分数。
并且使用 SQL 中的全文搜索可以快速、轻松地执行弹性搜索。这种执行模糊搜索并对结果进行排序的能力构成了任何搜索引擎的核心。这个特性最好的部分是索引可以被设置为在基本数据更新时自动更新。
除了使用它的搜索功能之外,我个人在许多 NLP 项目的开始使用了全文索引。例如,浏览索引和术语计数让我对特定领域的停用词有所了解。滚动索引并查看拼写错误的单词或错别字,给了我需要执行的文本清理步骤的线索。
谢谢你能走到这一步。我会写更多这样的帖子。让我知道你对这篇文章的看法,以及你希望通过在 LinkedIn 上给我发消息来了解的其他话题。以后的帖子,请关注我的媒体。
用 Amazon Lambda 和 API Gateway 构建一个无服务器 API
如何以最简单的方式托管可伸缩的无服务器 API
照片由 Unsplash 的 Saish Menon 拍摄。
目录
- 介绍
- 使用 GingerIt 创建一个拼写和语法纠正器
- 将 Python 服务部署到 Lambda
- 将 API 网关与 Lambda 相关联
- 使用 API 密钥保护和抑制 API
- 结论
- 参考
介绍
在我以前的文章“使用亚马逊 S3 和 Route 53 构建一个无服务器网站”中,我演示了如何构建一个由静态(客户端)内容组成的无服务器网站。这种方法允许轻松地将网站从 10 个扩展到 1000 个,同时保持低成本。
为了将无服务器扩展到动态(服务器端)内容,Amazon Web Services (AWS)提供了更多的服务,如 AWS Lambda。与 API Gateway 一起,我们可以创建 RESTful APIs,实现实时双向通信应用程序。
在这篇文章中,我们将介绍如何使用 AWS Lambda 创建和部署拼写和语法纠正应用程序,并通过 API Gateway 响应标准 HTTP 请求。
使用 GingerIt 创建一个拼写和语法纠正器
GingerIt 是一个人工智能驱动的开源 Python 包,它可以根据完整句子的上下文来帮助纠正文本中的拼写和语法错误。
要使用它,让我们首先创建一个虚拟环境,并在其中安装 GingerIt。
为了测试它,在终端中运行下面的代码片段。
这将显示原始文本,然后是由 GingerIt 修改的文本。
Original text: 'This is a corrects snetence'
Corrected text: 'This is a correct sentence'
将 python 服务部署到 Lambda
“AWS Lambda 是一种无服务器计算服务,让您无需配置或管理服务器就能运行代码(…)。Lambda 自动精确地分配计算执行能力,并基于传入的请求或事件运行您的代码(…)。你可以用自己喜欢的语言(Node.js、Python、Go、Java 等)编写 Lambda 函数,同时使用无服务器和容器工具,比如 AWS SAM 或 Docker CLI。”
Amazon 的上述声明总结了 Lambda 的目的:提供一个简单的服务,使用任何主要语言的定制代码对请求做出反应,并且不需要管理运行时。为了进一步促进 API 的开发和部署,Lambda 还支持 Docker。
为了部署 GingerIt 拼写和语法纠正服务,我们将利用 Lambda 的 Docker 支持。为此,我们首先需要将 Python 服务打包到 Docker 容器中。
让我们从创建 lambda 处理程序开始,每次执行 Lambda 函数时都会调用这个处理程序。这个处理程序将接收一个 json,其中包含我们想要修改的文本,用 GingerIt 处理它,并返回修改后的文本。将下面的代码片段另存为 app.py 。
现在我们只需将 app.py 文件包装在一个 Dockerfile 中,如下所示。请注意,您应该使用 AWS 支持的图像。这将确保正确设置执行 Lambda 所需的所有包。
要测试 lambda 函数,首先要构建并运行 docker 容器。
然后在终端或笔记本中运行下面的代码片段。
如果所有步骤都成功,您应该会看到以下输出。
{‘body’: ‘{“corrected_text”: “This is the correct sentence”}’, ‘headers’: {‘Content-Type’: ‘application/json’}, ‘isBase64Encoded’: False, ‘statusCode’: 200}
此时,我们知道本地 Lambda 工作正常。下一步是远程运行它(无服务器)。为此,我们需要:
- 将 docker 映像推送到 Amazon 弹性容器注册中心(ECR)
- 创建一个新的 Lambda 函数,并将其与 ECR 图像相关联
- 为 Lambda 函数设置 IAM 访问权限
幸运的是,通过使用*无服务器框架,整个过程(以及后面介绍的额外步骤)可以被简化。*要安装它,只需按照官方无服务器网站 ⁴.
安装完 serverless 后,创建一个名为 serverless.yml 的新文件,并在其中添加以下内容。
这个文件定义了 Lambda 中的关键参数。
**service**: Name of the service we are creating. This name will be user across all required resources.**provider:
name**: Name of cloud provider to use (AWS)
**stage**: Stage to use (dev, prod)
**region**: Region to where to deploy the lambda function
**runtime**: Runtime that will be used to run the docker container. the python version should match the docker one.
**ecr**:
**imager**:
**gingerit**: Target name for the docker image
**path**: Defines where the docker file is**functions:
gingerit**: Defines the parameters for the lambda function named ‘gingerit’
**timeout:**If request takes longer than the defined value, return time out
**memory_size**: Total docker RAM in Megabytes
**image:
name**: Name of the docker image to use. Must match provider.ecr.image
要部署我们的服务,我们现在只需在终端中调用无服务器部署。应该会出现以下输出(将映像部署到 ECR 和 Lambda 函数可能需要几分钟时间)。
Serverless: Stack update finished...
Service Information
service: language-corrector
stage: dev
region: eu-west-1
stack: language-corrector-dev
resources: 6
api keys:
None
endpoints:
None
functions:
gingerit: language-corrector-dev-gingerit
这个输出显示了我们的 lambda 函数的全名**(language-corrector-dev-gingerit)以及我们定义的一些变量。要测试该函数,请在终端或笔记本单元格中运行以下代码片段。**
应该可以看到以下输出:
**{'body': '{"corrected_text": "This is the correct sentence"}',
'headers': {'Content-Type': 'application/json'},
'isBase64Encoded': False,
'statusCode': 200}**
万岁!您刚刚创建了一个拼写和语法纠正工具,并将其部署为无服务器。
将 API 网关与 Lambda 相关联
“API Gateway 处理与接受和处理多达数十万个并发 API 调用相关的所有任务,包括流量管理、CORS 支持、授权和访问控制、节流、监控和 API 版本管理。(…) API Gateway 支持容器化和无服务器工作负载,以及 web 应用程序。”⁵
总之,API Gateway 充当了客户端浏览器和 Lambda 函数之间的中间人,接受并处理 HTTP 请求和响应。此外,它还可以用来设置每秒允许的调用次数的限制,或者给定函数或 api 键的每月上限。
要使用它,我们只需在无服务器的函数中添加一个 events 对象。我们新的无服务器看起来像这样:
事件对象定义了设置 API 网关所需的字段。
****http:** Defines the event as an HTTP method
**path:** Endpoint path name
**method:** HTTP method used to access this endpoint
**cors:** If true allows Cross-Origin Resource Sharing
**async:** Endpoint can be accessed async
**private:** Endpoint requires an API key to be accessed**
如果我们现在重新运行无服务器部署,则会出现一个新字段(端点)。这个字段指示 API 网关的地址,我们需要它通过 HTTP 请求调用 Lambda 函数。
**endpoints:
POST - [https://olx5ac31og.execute-api.eu-west-1.amazonaws.com/dev/language_corrector](https://olx5ac31og.execute-api.eu-west-1.amazonaws.com/dev/language_corrector)**
这表示我们需要通过标准 HTTP 请求调用 Lambda 函数的 API 网关地址。要测试新端点,请运行下面的代码片段。
如果成功实现了 API 网关,应该会出现正确的文本:
**{'corrected_text': 'This is the correct sentence'}**
使用 API 密钥保护和抑制 API
到目前为止,我们有一个部署在 Lambda 中的工作 API,它可以通过标准的 HTTP 方法接受请求。
然而,任何知道 URL 的人都可以访问这个函数,并且对每秒的请求数没有限制。这是很危险的,因为如果有太多的请求,它会很快增加你每月的花费。
为了减轻这种情况,我们可以在 API Gateway 中设置 API 密钥。要使用它,我们只需在无服务器中向我们的提供者添加一个 apiGateway 对象,并将我们的 events 对象中的私有标志设置为 true。我们新的无服务器看起来像这样:
apiGateway 对象为我们的 API 定义了使用计划。在这个例子中,我们设置了两个 API 键。一个有一些限制的免费 API 密匙,和一个允许每秒更多请求和更高上限的付费 API 密匙。
**apiGateway:
apiKeys:
- free: name of the usage plan
- name of the api key
usagePlan:
- free:
quota:
limit: Maximum number of requests in a time period
offset: The day that a time period starts
period: The time period in which the limit applies
throttle:
burstLimit: Rate limit over a short amount of time
rateLimit: API request steady-state rate limit**
如果我们现在重新运行无服务器部署,则会出现一个新字段( api 密钥)。该字段指示我们的新 API 密钥的名称和值。
**api keys:
medium-language-corrector-free: FREE_KEY
medium-language-corrector-paid: PAID_KEY**
要测试新端点,请运行下面的代码片段。
如果成功实现了 API 网关,应该会出现正确的文本:
**{'corrected_text': 'This is the correct sentence'}**
完成脚本
如需完整的脚本,请点击以下链接进入我的 GitHub 页面:
****https://github.com/andreRibeiro1989/medium/tree/main/spell_grammar_correction
结论
使用无服务器计算允许您在不管理 web 服务器的情况下扩展应用程序,同时保持低成本。
虽然对于静态内容,最简单和最实惠的选择是亚马逊简单存储服务(S3),但这种方法不允许我们使用动态服务器端代码。
为了将无服务器扩展到更复杂的应用程序,在本教程中,我们探索了如何使用 Amazon Lambda 和 API Gateway 来部署无服务器拼写和语法纠正工具。
这个简单的例子将为您提供构建更复杂的应用程序所需的所有工具,比如无服务器聊天机器人或图像处理服务。****
如果你喜欢阅读这样的故事,并想支持我成为一名作家,可以考虑报名成为一名媒体成员。每月 5 美元,让你可以无限制地访问 Python、机器学习和数据科学文章。如果你使用我的链接注册,我会赚一小笔佣金,不需要你额外付费。
****https://andrefsr.medium.com/membership
参考
[1] A .里贝罗。“用亚马逊 S3 和 Route 53 搭建一个无服务器网站”
https://towardsdatascience . com/Build-a-server less-website-using-Amazon-S3-and-Route-53-c 741 FAE 6 ef 8d
[2] T .克莱因施密特。"欢迎使用 Gingerit 的文档!(2015)
https://gingerit.readthedocs.io/en/latest/
[3]亚马逊团队。AWS Lambda
https://aws.amazon.com/lambda/
[4]无服务器团队。无服务器框架—文档
https://www.serverless.com/framework/docs/getting-started
[5]亚马逊团队。亚马逊 API 网关
https://aws.amazon.com/api-gateway/****
在 GCP 建立一个无服务器的交付指挥中心
结合地图,或工具,发送网格和云功能来征用一个送货车队
本文展示了如何:
1.在 GCP 建立一个云存储,当文件上传时触发云功能;
2.用谷歌地图和谷歌 OR-Tools 设置一个计算最优路线策略的云功能;
3.通过 SendGrid 向承运人发送说明电子邮件;
4.为持续部署设置云构建。
令人惊讶的是,仅仅通过几项服务就可以在云上构建许多现代商业解决方案。开发人员可以将云组件结合起来,构建一个从数据接收到通过电子邮件发送结果的管道,只需点击几下鼠标。价格很灵活。硬件配置最少,尤其是使用无服务器选项时。因此,小型企业现在可以负担起大量的计算能力。计算能力的民主化使许多传统企业迅速现代化。其中之一一定是送货服务。
图一。Joshua Fernandez 在 Unsplash 上的照片
我在 Medium 上看到了两篇文章:一篇是由 Sebastian Telsemeyer 写的,关于用 Cloud Run 和 Pub/Sub 在 GCP 建立一个时间序列预测管道;
第二个是由 Samir Saci 提出的,他使用 Goolge OR-Tools 来优化最后一英里的交付(然而解决方案是由 Goolge 在 2020 年首先提出的):
塞巴斯蒂安的文章鼓舞人心。在他的管道中,一个 Pub/Sub 监控一个特定的 GCP 桶。上传 TSV 文件时,它会激活云运行计算,在第二个存储桶中生成结果。他的整个基础设施是无服务器的,并且是用 Terraform 编码的。在我看来,他的管道甚至可以更简单:一个Finalise/Create
事件触发的云函数,可以代替“Pub/Sub + Cloud Run”组合。更简单的版本需要更少的设置。因为云函数基本上是一个 Lambda 函数,所以它摆脱了整个 Docker 部分和 Gunicorn + Flask 依赖关系。
Samir 的文章展示了一个复杂的有容量限制的车辆路线 问题 (CVRP)如何通过 Google OR-Tools 解决。让我们假设有 30 个包裹需要由两个承运人从德国布伦瑞克的一个物流中心分发到九个不同的地方。每个承运人最多可以承运 15 个包裹。然后,Google OR-Tools 会尝试以最低的成本规划路线,同时平衡每个承运人的负载和距离。示例输出如下所示:
Hello Driver A, your delivery route is:
bring 2 Parcels to Institute of System Security, Muehlenpfordtstrasse 23, 38106 Braunschweig ->
bring 2 Parcels to Am Schuetzenpl. 1, 38114 Braunschweig ->
bring 3 Parcels to Humboldtstrasse 1, 38106 Braunschweig ->
bring 2 Parcels to Johanniterstrasse 5, 38104 Braunschweig ->
bring 6 Parcels to Willy-Brandt-Platz 1, 38102 Braunschweig ->
OR 工具将十个位置的距离矩阵作为输入之一。在谷歌的原始帖子和萨米尔的文章中,距离矩阵是虚构位置的硬编码虚拟物,路线指示只是以文本形式打印出来。在真实的配送指挥中心,我们需要根据真实地址计算距离矩阵(见我之前的文章此处)并通知承运人他们的路线。
图二。GCP 交付精简版架构。由onlinewebfonts.com承运图标,由 CC 3.0 授权。图片作者。
带着这些想法,站在 Sebastian 和 Samir 的肩膀上,我接受了挑战,并在 GCP 实施了一个简单的解决方案。云存储中的上传事件可以触发云函数通过 Google Maps API 构建距离矩阵。或工具然后计算路线。最后,它通过 SendGrid 将路线指示发送给运营商(图 2。).作为奖励,我设置了云构建来持续部署应用程序。这个项目的代码存放在我的 Github 库中。
https://github.com/dgg32/gcp-delivery-lite
1.准备输入 Json 数据
输入的 Json 数据包含两部分。第一部分包含所有位置的地址和包裹数量。第一个位置总是承运人装载包裹的物流中心。第二部分是承运人的信息,包括他们的姓名、能力和电子邮件地址。下面是我的 input.json 的缩略版。
2.设置发送网格
我们希望通过云功能向运营商发送说明电子邮件。Goolge 建议我们使用可信的第三方提供商,比如 SendGrid。SendGrid 中的免费计划允许每天 100 封邮件永远免费,这对我们的项目来说足够了。
图 3。发送网格 API 设置。图片作者。
图 4。通过整合测试。图片作者。
首先,用免费计划在 SendGrid 中注册一个账户。然后创建一个发送者身份。这是电子邮件中的“发件人”地址。之后,SendGrid 会向您发送一封电子邮件。在发送电子邮件之前,您需要验证您的单一发件人是否遵循其说明。
然后导航到用户仪表盘,点击打开Email API
和Integration Guide
。选择Web API
和Python
。然后创建一个 API 键(图 3。)并遵循测试说明,直到您通过集成测试(图 4。).将单个发件人的电子邮件和 API 密钥保存在安全的地方,以备后用。
3.建立 GCP
在你的 GCP 控制台上创建一个名为delivery-lite
的项目。启用Distance Matrix API
并为其创建一个限制性 API 密钥。这个过程涉及到许多点击,你可以在这里阅读我以前的文章获得指导。
然后转到Cloud Function
并创建一个函数command-center
,选择Cloud Storage
作为触发类型,选择Finalize/Create
作为事件。单击“浏览”并创建一个存储桶。点击SAVE
。
图 5。云功能配置。图片作者。
展开RUNTIME
设置,添加四个环境变量:
KEY
是你的距离矩阵 API 键。SENDGRID_API_KEY
是您的 SendGrid API 密钥。SENDER
是您的单一发件人电子邮件地址。PROJECT
是项目名称,在本例中是delivery-lite
。
然后可以点击NEXT
按钮进入Code
页面。启用Cloud Build API
,并按照警告横幅中的说明创建凭证。完成后,返回到Code
页面。选择Python 3.9
作为运行时,输入main
作为进入点。
在内嵌编辑器中创建一个名为function.py
的文件。将我的存储库中的内容复制并粘贴到相应的文件中(图。6).或者你可以压缩并上传我的三个文件。按下DEPLOY
按钮,等待功能就绪。
图 6。定义云函数。图片作者。
function.py
包含三个辅助功能。前两个用于通过 Maps API 计算地点列表的距离矩阵。第三个通过 SendGrid 发送电子邮件。
main.py
利用了function.py
。在第 12 行收到距离矩阵后,脚本将它与运营商信息打包在一起,最后在第 29 行调用 OR-Tools。如果找到了至少一个解决方案,脚本将制定路线指令,并通过第 46 行的 SendGrid 分别发送给每个承运人。在此,我感谢 Samir 和 Google 团队提供的 OR-Tools 代码示例。
4.测试管道
设置好一切之后,我们现在可以测试管道了。下面是input_test.json
文件。修改carrier
列表中的信息,特别是在email
字段中输入有效的电子邮件地址,以便接收输出指令。打开云存储页面的一个新选项卡,找到指定的存储桶。将input_test.json
文件上传到 bucket 中(图 7。).这应该会触发我们的云功能运行。
图 7。将输入数据上传到指定的桶中。图片作者。
如果一切顺利,您可以在云功能页面的LOGS
中看到新的日志条目。它们是脚本的标准输出(图 8。).
图 8。成功执行管道的日志。图片作者。
你可以查看你的运营商的电子邮件。一封包含路由说明的新电子邮件应该很快就会到达(图 9。).
图 9。带有路线说明的电子邮件。图片作者。
5.为持续部署设置云构建
使用云构建建立一个连续部署(CD)管道是非常容易的,这样新的修改就可以被自动和立即地部署。首先,建立一个 Github 存储库,并用这三个文件初始化它。或者你可以直接转到我的知识库。你还需要先启用[Cloud Resource Manager](https://medium.com/ci-t/how-to-set-up-a-deployment-pipeline-on-gcp-with-cloud-build-and-cloud-functions-88ef485728f9)
API。
图 10。云构建触发器设置。图片作者。
接下来,导航到Cloud Build
页面。创建一个名为CICD-delivery
的触发器。选择你的 Github 库和Source
的^master$
分支(你需要按照 GCP 的指示连接你的 Github 库)。选择Cloud Build configuration file (YAML or JSON)
,点击CREATE
。最后,在 Settings 选项卡中,启用Cloud Functions Developer
角色。
然后,确保文件cloudbuild.yaml
位于您的存储库的顶层,并且包含以下内容:
该文件指示 Cloud Build 使用正确的区域、存储桶触发器和运行时来部署应用程序。从现在开始,每当你向存储库推送新的变更时,GCP 将自动构建管道并将其部署为云功能。
结论
成功!现在,我们有了一个简单的管道,作为递送业务的神经中枢。手动调度已经成为过去。每当您将新订单或新承运商的新 Json 文件上传到桶中时,云功能将自动计算最佳路线,并通知登记的承运商他们的指令。并且只有在运行时才会产生成本。此外,CD 管道确保您的更改可以自动部署。
承认,这个设计是我的指挥中心理念的一个基本实现。您可以在其中构建更多组件,使其更加强大。例如,一旦用完可用层配额,距离矩阵的成本可能会失控。如果我们能够将成对距离存储在数据库中,那就太好了。此外,我们可以将运营商放入一个池中,以便更好地管理他们的个人数据。
即使有了所有这些扩展,管道仍然只是一个大型现实世界优化问题的简单抽象。OR 工具假设所有的订单都是已知的,并且在路线开始之前所有的承运人都已经在物流中心等待。在现实世界中,订单源源不断,承运人无处不在。但我认为,这些违规行为只会对结果产生轻微影响,管道仍然可以保持畅通。此外,距离有时并不是成本计算的最佳替代。幸运的是,距离矩阵 API 也返回两个地方之间的行驶时间,值得进行一些测试,看看哪个度量更好。
此外,我可以想象我们可以从这条管道中创造出非常不同的东西。因为谷歌或-Tools 可以计算其他类型问题的解决方案,我们可以将管道转化为汽车共享指挥中心、公交路线设计师、班次规划服务甚至饮食计算器。
因此,现在是时候让你在这条管道上进一步构建一些东西,并向我展示你的想法。
https://dgg32.medium.com/membership
使用亚马逊 S3 和 Route 53 建立一个无服务器网站
如何在 15 分钟内托管一个可扩展的网站
图片来自 Unsplash 上的迭戈·希门尼斯。
目录
- 介绍
- 在亚马逊 S3 主持一个网站
- 将自定义域与 Amazon Route 53 相关联
- 在线主持个人作品集
- 结论
- 参考
介绍
你有没有想过建立自己的网站?也许是为了展示你的工作、你的业务,或者只是一种在线展示的方式?
对于大多数应用程序来说,网站可以只用客户端代码运行,并且只由 HTML、CSS 和 JavaScript 组成。这类网站通常被定义为静态网站。由于没有运行或维护服务器端代码,使用传统的 web 服务器毫无意义。
Amazon Web Services (AWS)为托管静态或动态网站提供了多种选择。对于静态内容,最简单和最实惠的选择是亚马逊简单存储服务(S3)。
在这篇文章中,我们将介绍如何创建一个 S3 桶,并为虚拟主机设置它,将 S3 端点指向一个自定义域,并创建一个简单的投资组合网站。
在亚马逊 S3 主持一个网站
‘亚马逊简单存储服务(亚马逊 S3)是互联网存储。它旨在使网络规模的计算更容易。亚马逊 S3 有一个简单的网络服务界面,你可以用它在任何时间从网络上的任何地方存储和检索任何数量的数据。’
亚马逊的上述声明总结了 S3 的目的:提供一个简单的接口,以高度可扩展和可靠的方式存储和检索数据。不仅如此,将数据存储在亚马逊 S3 是一个可行且负担得起的解决方案。
这些关键优势加上不需要网络服务器,使得亚马逊 S3 成为静态虚拟主机的理想服务。让我们潜入亚马逊 S3,托管我们的第一个网站。
为虚拟主机创建和配置 S3
第一步是创建一个 S3 桶来存储我们的网站文件。为此,请导航至 S3 界面,然后单击“创建时段”。
S3 接口。图片由作者提供。
在“常规配置”部分,将“存储桶名称”定义为“投资组合”。#DOMAIN_NAME# '。这将是你的投资组合的主页链接。将#DOMAIN_NAME#替换为您拥有的域名。如果您没有域和/或不想创建域(查看下一节如何注册域),这可以是 rfc3986 中允许的任何字符序列。
在下一部分中,取消选中“阻止所有公共访问”。这将允许用户检索存储在 S3 存储桶中的静态页面。
选中警告框“关闭阻止所有公共访问可能会导致此存储桶和其中的对象成为公共的”,然后单击“创建存储桶”。
在 S3 创建一个新的存储桶。图片由作者提供。
单击您刚刚创建的存储桶名称,然后转到“属性”。向下滚动并点击“静态虚拟主机”部分的“编辑”按钮。
在此窗口中:
- 在“静态网站托管”中选择“启用”
- 在“托管类型”部分保留默认的“托管静态网站”
- 在“索引文档”中键入“index.html”
- 单击保存更改
改变 S3 桶到静态网站托管。图片由作者提供。
转到“权限”部分,向下滚动并单击“存储桶策略”部分中的“编辑”按钮。在文本框中,键入以下策略,然后单击“保存更改”。
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "AllowPublicRead",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::portfolio.#DOMAIN_NAME#/*"
}
]
}
您的存储桶策略应该是这样的。
添加 S3 策略以允许公共读取访问 S3 存储桶。图片由作者提供。
上传数据并测试网站端点
仍然在您创建的 S3 存储区中,移动到“对象”部分,上传一个名为“index.html”的新文件,其内容如下:
<html>
Hello World!
</html>
您可以用任何文本编辑器创建这个文件。请确保将其命名为“index.html”。您的 S3 桶现在应该看起来像这样。
为静态虚拟主机配置的 S3 桶包括一个样本 index.html。图片由作者提供。
我们可以通过打开以下链接来测试网站是否工作:
http://portfolio。# DOMAIN # . S3-website-eu-west-1 . Amazon AWS . com
测试新创建的静态虚拟主机。“Hello World”消息表明“index.html”文件已成功检索。图片由作者提供。
好吧!我们刚刚创建了一个工作网站。我们缺少的是这个端点和一个自定义域之间的链接。
如果您有自己的域,或者现在想使用 Route 53 创建一个域,请转到下一部分,将我们新创建的端点链接到该域。否则,转到“在线托管个人投资组合”部分,创建您的第一个投资组合网站。
将自定义域与 Amazon Route 53 相关联
Amazon Route 53 是一个高度可用和可扩展的云域名系统(DNS)service⁴.Amazon Route 53 可用于将自定义域路由到任何 AWS 服务(如 S3 端点)。推荐使用该服务,因为它可以轻松地与许多 AWS 服务(如 S3、CloudFront 或 EC2)集成。
亚马逊路线 53 主页。图片由作者提供。
虽然您可以通过多个提供商注册一个域,但 Amazon Route 53 也提供了一种注册自定义域的简单方法。使用 53 号公路简化了从注册域名到托管网站的整个过程。
向 Route 53 注册自定义域
要注册域名,请导航至 Route 53 主页,然后点击“开始”。点击“注册一个域”,键入您想要注册的域,如果可用,将其添加到购物车。最后,添加如下所示的详细信息,并完成注册过程。
亚马逊 53 路的域名注册页面。图片由作者提供。
当您使用 Route 53 注册一个域时,AWS 会自动为该域创建一个“托管区域”,并在域注册年费之外对托管区域收取少量月费。
如果您决定不使用 Route 53,您可以在注册域名的 12 小时内删除托管区域,并且不会为此向您收费。在本教程中,我们将假设您将使用 Route 53 来处理端点和您的域之间的路由。
自定义域注册后的 Route 53 接口示例。图片由作者提供。
将自定义域与 S3 端点相关联
要链接之前创建的 S3 端点,请点击 Route 53 主页中的“托管区域”,然后点击您的域,最后点击“创建记录”。
在这个新窗口中,在“记录名称”中键入“投资组合”,并按如下方式匹配其余字段。确保自动识别的 S3 存储桶与我们刚刚创建的存储桶相匹配。最后,点击“创建记录”。
创建 Route 53 记录以将 S3 web 宿主端点链接到自定义域。图片由作者提供。
现在让我们来测试我们的定制域的投资组合。#域# ’
测试到 S3 web 宿主端点的自定义域链接。“Hello World”消息表明“index.html”文件已成功检索。图片由作者提供。
很好。我们设法创建了一个功能齐全的网站托管在 S3,并链接到我们的自定义域。现在,你只需要将你的内容添加到 S3,它将在你的网站上随时可用。
在线主持个人作品集
为了完整起见,让我们下载一个引导文件夹模板,并将其添加到我们的网站。
要做到这一点,去 https://startbootstrap.com/theme 的下载他们免费的自由职业者模板(或者任何你喜欢的模板)。
Start Bootstrap 免费提供的作品集模板快照。
在本地提取 zip 文件的内容,并将文件拖放到您创建的 S3 存储桶中。
S3 上传界面。图片由作者提供。
最后刷新你的网站,你的新作品集应该会出现。
在新创建的 web 服务中运行的项目组合模板。图片由作者提供。
结论
托管一个静态网站从来没有这么容易。
亚马逊 S3 提供了一个简单的界面,以灵活、可扩展、快速和廉价的方式存储和检索大量数据。
同时,Route 53 简化了定制域的创建和路由,并且非常容易与 S3 和其他 AWS 服务集成。
似乎这还不够,AWS 为前 12 个 months⁵.使用 S3 的新用户提供了一个免费层因此,如果你的网站低于 5GB,你只需支付域名注册和托管区。
参考
[1]亚马逊团队。"什么是亚马逊 S3?
https://docs . AWS . Amazon . com/Amazon S3/latest/user guide/welcome . html
[2] T. Berners-Lee 等.统一资源标识符(URI):通用语法(2005)
https://www.ietf.org/rfc/rfc3986.txt
[3]亚马逊团队。“设置网站访问权限”
https://docs . AWS . Amazon . com/Amazon S3/latest/user guide/websiteaccesspermissionsreqd . html
[4]亚马逊团队。亚马逊路线 53
https://aws.amazon.com/route53/
[5]亚马逊团队。" AWS 自由层【https://aws.amazon.com/free/?all-free-tier】"
构建一个简单的 Web 应用程序来分类 50 美元和 100 美元的钞票
使用 Jupyter 笔记本从模型到生产
“作者提供的图像”
你有一张 50 美元或 100 美元的钞票,关于这张钞票的一些事情引起了关注,你想检查这张钞票是不是假钞,如果你有一个应用程序,可以上传钞票的照片并立即得到结果,这不是很方便吗?如果你能为自己造一个呢?你可能会说,既然市场上已经有很多其他选择,为什么还会有人开发这样一款应用。好了,这就把我们带到了人工智能和深度学习的话题上。这篇文章不是关于一个应用程序或想法是否是原创的,而是关于如何使用 fastai 深度学习库和 voila 创建有用的模型并将其部署在网络上。在这篇文章中,我将分享我是如何建立我自己的美国钞票分类器的,通过遵循说明,你也许可以建立一个甚至更好的分类器,或者赋予你独特的想法以生命。话虽如此,我将要提供的代码和指令可能适用于类似的问题,然而,相同的代码和技术并不适合所有的解决方案。
深度学习模型
在这个 50 美元和 100 美元分类模型的背景下,该模型将分类或预测图像是 50 美元还是 100 美元的钞票,就像我们人类可以用我们的视觉区分或识别物体一样。例如,一个孩子看到一只鸟向窗外望去,可以立即认出羽毛、喙以及与标签“鸟”相关的特征。孩子以前见过鸟,两个重要的方面来自孩子对鸟的识别或辨认机制:1)鸟的特征,如羽毛、喙、翅膀、形状、颜色等。以及 2)与那些特征相关联的标签“鸟”。类似地,该模型以带有标签的图像形式提供数据——“50 美元”或“100 美元”,然后学习这些图像的特征,例如边缘、颜色、梯度等。一旦模型已经从数据中学习,当呈现学习数据中不包括的图像时,它仍然可以识别对象!假设我们为模型提供每种类型的 100 张图片,总共 200 张带有标签的图片。然后我们可以要求模型(以编码的形式提供参数)取每种类型的 80 幅图像(标签)来学习特征(每种类型的 80 幅图像,总共 160 幅图像被称为训练数据),并留出模型没有看到的其余图像(未看到的图像组被称为验证集)。验证集用于检查模型已经学习了多少。如何检验模型是否准确?有一些方法可以用来验证模型的口径。我们将继续研究这些方法。使用标签区分图像的过程称为分类。深度学习是基于人脑功能的人工智能的一个子集。我们的大脑中有数十亿个神经元,它们相互发送信号和信息,让我们能够理解周围的环境。深度学习模型利用数据来检测物体、语音、语言,并在没有人类监督的情况下做出决策。
图 1:神经网络的演示(“作者图片”)
对于我们的模型,我们将使用 CNN 或卷积神经网络。简而言之,神经网络由分层包装在一起的人工神经元组成。每一层都由许多神经元组成,这些神经元将图像分解成非常小的部分并寻找模式,这些神经元中的每一个都与下一层中的所有神经元相连,以便它们可以传递它们获得的信息。一层一层地,神经元将所有的碎片放在一起,创建一个有意义的图像(见上面的图 1)。CNN 应用于图像分类问题,好消息是你不必创建任何算法,计算机会为你做所有的计算!
我试图提供这些概念的 10,000 英尺水平的视图,要真正掌握对这些概念的全面理解,我建议您探索大量可用的在线资源和书籍。我可以推荐访问: Fast.ai 这是目前最好的深度学习免费课程之一。虽然该课程是针对那些已经有一些编码经验的人,但它也是新手获得全面理解的一个很好的课程。
功能和限制
我们将要创建的这个模型将是一个很好的练习,可以帮助我们理解这项技术的一些功能和局限性。如前所述,我们将应用 CNN 模型来对 50 美元和 100 美元钞票进行分类,这将需要具有标签的图像形式的数据。模型的效力在很大程度上取决于我们提供的数据。一张钞票有许多复杂的细节,如全息图和只有在紫外光下才可见的特征。这意味着您要么必须拍摄将这些要素纳入视野的照片,要么找到包含这些类型图像的数据集。我没有使用过这样的图片,我将提供我如何创建模型并在网上部署它的说明。但是你已经可以猜到有很多机会让你调整和改进模型,也可以估计一些与这项技术相关的挑战和限制。过多或过少的数据是另一个约束,称为过度拟合,会导致模型效率低下。那么,当您为模型提供与用于训练模型的图像完全不同的图像时,会发生什么呢?该模型在预测方面表现不佳,例如,当使用彩色图像训练模型时,输入黑白图像进行分类可能会突出缺陷。这个模型只能识别它所看到的,或者与相似的图像和物体进行类比。但是,我的模型用我提供的数据取得了显著的效果。理论上的东西说够了,现在让我们开始吧!
设置环境
我提供的指导正是我创建和部署这个模型的方式。还有其他方法可以达到同样的效果。由于这是一个使用深度学习库的深度学习模型,你需要在你的计算机上安装一个 NVIDIA GPU(图形处理单元),但是,我使用并建议使用 GPU 服务器。
- 第一步:创建一个免费的 Paperspace Gradient 账户,按照的指示操作。创建帐户后,为您的项目创建一个 jupyter 笔记本文件夹和一个笔记本文档/IPYNB 文件。
- 第二步:创建一个免费的微软 Azure 账户。一旦帐户被创建,你将得到一个 API 密钥,保存在某个地方以备后用(非常重要!).
下载图片
从上面第 2 步的 Microsoft Azure 帐户中复制 Bing 图像搜索 API 密钥,并将其粘贴到显示将您的 API 密钥粘贴到此处的区域:
注意:您将使用 Bing 图像搜索 API 键来搜索带标签的图像,并将它们下载到您的笔记本上。下载的图像将成为您的数据集。
套餐
使用以下代码导入包:
粘贴您的 API 密钥:
使用以下功能在 Bing 中搜索图像:
使用下面的代码下载 50 美元和 100 美元的图像:
使用以下代码检查您的文件夹,确保其中包含图像文件:
您的输出应该是这样的。
有时,从互联网下载的文件可能会损坏,要检查此类文件,请使用以下代码:
要删除任何失败或损坏的图像,请使用以下代码:
数据加载器&数据块我们下载的图像存储在文件夹中,如您在前面的步骤中所见。为了使这些数据对模型可用,需要创建一个 DataLoaders 对象。DataLoaders 是一个 fastai 类。要将下载的数据转换成 DataLoaders 对象,我们至少需要告诉 fastai 四件事:
我们正在处理哪些类型的数据?如何获取物品清单?这些物品怎么贴标签?如何创建验证集?
为了定制数据加载器,我们将使用称为数据块 API 的东西,下面是使用数据块定制数据加载器的代码(检查代码中的注释,了解每个参数)。
使用以下代码,使用账单数据块指向图像目录:
数据加载器一次成批处理几个项目,并将其提供给 GPU。数据加载器具有培训和验证数据加载器,使用下面的代码查看一些项目:
数据扩充
使用 fastai 函数可以应用多种技术来处理图像,如挤压、填充等。但是这些技术可能会导致关键特征的丢失。例如,如果我们挤压或填充一张 100 美元钞票的图片,可能会导致关键特征的丢失,或者使钞票看起来与实际钞票不同,这反过来会降低模型的准确性。我将只提供我用来创建我的模型的技术。数据扩充是指创建我们输入数据的随机变化,这样它们看起来不同,但实际上并不改变数据的含义。常见的图像数据增强技术的例子有旋转、翻转、透视扭曲、亮度变化和对比度变化。对于自然照片图像,如我们在这里使用的,aug_transforms 函数提供了一套标准的增强功能,效果非常好。因为我们的图像现在都是相同的大小,我们可以使用 GPU 将这些放大应用于整批图像,这将节省大量时间。这里有一个我上面刚刚描述的例子,我们使用 RandomResizeCrop。要传入的最重要的参数是 min_scale,它决定了每次至少要选择多少图像。使用下面的代码查看示例:
我们使用 unique=True 让相同的图像在不同版本的 RandomResizedCrop 转换中重复。这是一个更一般的技术的具体例子,称为数据扩充。对于我们的问题,我们没有太多的数据(每种熊最多 150 张照片),所以为了训练我们的模型,我们将使用图像大小为 224 px 的 RandomResizedCrop,这对于图像分类来说是相当标准的,默认的 aug_transforms:
型号
现在我们已经准备好了数据,我们可以训练和测试我们的模型。我们需要创建一个学习器,它将使用函数 cnn_learner,该函数需要一个数据集,在我们的情况下,它是 dls ,一个架构,我们将使用一个预训练的 18 层神经网络,称为 resnet18 ,以及一个度量,它将是 error_rate,给我们错误分类的百分比。使用下面的代码创建学习者:
现在,您应该会看到如下统计数据:
世
时期是模型通过训练数据的迭代次数。如前所述, error_rate 是我们模型准确性的关键指标(准确性= 1-error_rate)。在最后一次迭代中,error_rate 是 0.096154,这意味着精度是 1–0.096154 = 0.903846 或 90.3% ,这已经很不错了!损失是训练集上的误差。loss 和 error_rate 之间是有区别的,loss 的整个目的是定义一个“性能度量”,训练系统可以使用它来自动更新权重。权重和梯度下降是神经网络的一些重要方面,我可能会在另一篇博客文章中介绍。
注意:您的历元结果可能会有所不同
我们将使用另一种方法来检查模型所犯的错误,我们将使用一个混淆矩阵。使用以下代码运行混淆矩阵:
现在,您应该会看到这样一个矩阵:
“作者提供的图像”
行代表我们数据中的 100 美元和 50 美元,列代表预测。对角线单元给出正确的预测,非对角线单元给出误差。所有 50 美元的预测都是正确的,100 美元的预测有 5 个错误。
使用下面的代码查看模型做出错误预测的图像:
现在,您应该会看到类似这样的内容:
哎呀!一张 100 美元的钞票上有唐纳德·特朗普!难怪模型会出错!
接下来,您可以使用下面的代码选择删除不正确预测的图像:
现在,您应该会看到类似这样的内容:
一旦您决定进行更改、保留或删除图像,请运行以下代码:
将您的模型转化为应用
一旦你成功地完成了上面的所有步骤,你的模型就可以变成任何人都可以访问和使用的实际应用程序了。要将模型转换成应用程序,首先需要将模型导出为**。pkl** 文件。使用下面的代码创建您的。pkl 文件,该文件应该出现在您的项目文件夹中。
现在您已经有了一个训练好的模型和一个. pkl 文件,我们只需要创建一个推理来获得预测。使用下面的代码创建一个推理:
使用下面的代码,通过一个名为 ipywidgets 的 GUI 组件创建一个上传按钮:
执行完代码后,您应该会看到一个上传按钮,如下所示:
上传按钮
您可以使用此上传按钮从您的设备上传图像文件以进行预测。如果你有一张 50 美元或 100 美元的钞票,拍一张照片并从你的电脑上传来测试模型,或者你也可以从互联网上下载随机的 50/100 美元的图片进行测试。只有 50 或 100 美元的图像会产生有意义的结果。使用以下代码显示您上传的图像。
我上传了一张 100 美元的图片,你上传的图片应该是这样的:
要使用标签获得图像的预测,请使用以下代码:
输出应该是这样的:
模型预测我上传的图片是 100 美元,准确率 94.78%!万岁!这个模型起作用了,现在它变成了一个应用程序!下一步是安装 voila ,voila 是一个 python 库,它通过隐藏代码单元,只显示小部件按钮和输出,将 jupyter 笔记本转换为 web 应用程序。使用以下代码安装 voila:
将笔记本转换成网络应用
成功完成上述步骤后,打开一个新的 jupyter 笔记本文档,只使用下面的代码。代码只包含创建应用程序所必需的内容,即小部件、事件处理程序、调用。pkl 文件,一个 vbox,将小部件和输出放在一起。我使用 markdown 文本来描述我的应用程序,使用以下代码来创建您的应用程序:
部署
完成上述所有步骤后,您就可以与全世界分享您的应用程序了!也可以免费做。这个应用程序将只在我的指示桌面上工作,而不是在智能手机上。按照以下步骤进行部署:
- 创建一个 GitHub 库。
- 将笔记本(包含应用程序的笔记本)添加到您的 Git 存储库中。
- 添加。pkl 文件并创建一个需求文件。
- 导航到活页夹将所有东西放在一起。
- 将文件下拉列表改为选择 URL。
- 在“要打开的 URL”字段中,输入
/voila/render/name.ipynb
(用笔记本的名称替换name
)。 - 单击右下角的点击板按钮复制 URL 并粘贴到安全的地方。
- 单击启动。
注意:binder 构建和启动需要一段时间
我希望你喜欢我的帖子,并祝贺你建立了一个深度学习模型并部署它!!
我想引用史蒂夫·乔布斯的一句话来结束这篇文章——“保持饥饿”。呆呆
参考资料:
免费在云上构建一个简单的零停机 NLP web 应用程序
为了检测输入消息的情感和得分
背景
让我们先快速看一下我的原型做了什么:
图片由作者制作,gif(内)由 QooBee 制作,图标(内)由 Pixel perfect 制作
本文将关注我们如何将这个基于情感分析的 NLP web 应用程序部署到云中。如何为这个项目构建 NLP 模型的深入主题将在以后的文章中讨论。该模型是使用以下数据源和模型构建的。
来源数据:来自 twitter api 的 1,600,000 条标签推文
型号:后勤补给
文本矢量器:哈希矢量器
介绍
先决条件
- 一个免费的 Heroku 账号https://www.heroku.com/free—强烈推荐获得验证以免费获得1000 小时/月,这允许您的单个应用程序零停机,因为只有大约 740 小时/月。
- 一个免费的 cron-job 帐户https://cron-job.org/en/——设置一个定期唤醒 web 应用程序的作业。
- Python 和 web 框架的基础知识(GET/POST)。
脚本架构
脚本架构
脚本文件的功能
Heroku 相关文件的功能
部署
1.从我的 Github 资源库链接的 medium-article 分支下载资源库:https://Github . com/cmy 113/sensation-analysis-project/tree/medium-article
2.登录https://dashboard.heroku.com/apps并创建一个新应用。输入您唯一的应用程序名称,并选择离您最近的地区。
从 Heroku 创建新应用
从 Heroku 创建新应用
3.使用以下链接在本地下载并安装 Heroku CLI:https://devcenter.heroku.com/articles/heroku-cli
4.导航至应用程序的部署部分,并遵循使用 Heroku Git 部署中的说明
Heroku 从 Heroku 部署
登录 heroku,导航到您在步骤 1 中从 Github 下载的项目目录,初始化 git,定义远程分支,添加所有文件,提交并最终推送到 Heroku
从 Heroku 使用 Heroku CLI
如何使用 Heroku CLI 进行部署
5.web 应用程序现在已经启动并运行,让我们导航到该网站,看看它是否按预期工作。
图片由 Heroku 和作者制作,gif(内)由 QooBee 制作,图标(内)由 Pixel perfect 制作
8.[可选]还记得我们提到过我们想要一个零停机应用吗?为了实现这一点,我们需要定期唤醒 web 应用程序,因为 Heroku 会在应用程序 30 分钟不活动后让其进入睡眠状态。当然,这将消耗你 24*31 = 744 小时的免费 dyno 小时。如果您想使用免费的 dyno 小时构建不同的 web 应用程序,请跳过这一步。
登录到https://cron-job.org/en/。单击 CREATE CRONJOB 并输入以下内容:
从 cron-job.org创建克朗乔布
然后,我们可以看到,根据历史记录,GET 请求被成功执行
cron-job.org 的克朗乔布历史
9.搞定了。耶!我们设法以零成本构建零停机 NLP web 应用程序并将其部署到云中!
你能进一步修改什么
因此,在快速了解了如何部署示例 NLP web 应用程序之后,下一个问题是:**如何从中获得更多的好处?**你可以使用这个库作为你现有 NLP 项目的启动,或者你可以在它的基础上修改额外的 5 东西:
- 将 Heroku 应用与 GitHub 集成,可以在 GitHub 上forkmyrepository并与 Heroku 同步。注意,我在本文的演示中使用了中型文章分支,我可能会对我的主分支做一些不定期的更新。
在 Heroku 中,您可以启用自动化部署,从而允许您在每次推送至 Github 存储库时重新创建 web 应用程序!我觉得这很神奇!😃
来自 Heroku 的 Github 和 Heroku 之间的集成
2.你需要在你的本地环境中安装一个虚拟环境来本地修改/测试我现有的代码。您可以按照下面概述的示例步骤来创建所需的虚拟环境。
# Assume you have installed python 3 in your local environment
# I am using python 3.8.5 for this project but the project should work for any version of 3.8
# Can refer to this tutorial here as well on how to create virtual env [https://www.youtube.com/watch?v=N5vscPTWKOk](https://www.youtube.com/watch?v=N5vscPTWKOk) # Identify where your python3 path is
# e.g. /usr/local/bin/python
which python# Install virtualenv package
pip install virtualenv# Navigate to home directory
# Create an Environments directory that stores all your virtual environment
# Navigate to Environments directory for the next step
cd
mkdir Environments
cd Environments # Create an empty virtualenv named sentiment-analysis-project
virtualenv -p /usr/local/bin/python sentiment-analysis-project# Activate the virtual environment
source sentiment-analysis-project/bin/activate # Navigate to downloaded project repository from Github
# Install project dependency from requirements.txt in the virtual environment
cd Downloads/sentiment-analysis-project-medium-article
pip install -r requirements.txt# You might need to download wordnet from nltk if you have not done it before. Open python terminal and run below command:
# python
# import nltk
# nltk.download('wordnet')
# Please follow this if you have trouble installing the nltk dataset
[https://stackoverflow.com/questions/38916452/nltk-download-ssl-certificate-verify-failed](https://stackoverflow.com/questions/38916452/nltk-download-ssl-certificate-verify-failed)# Finally trigger the application
python wsgi.py# Yay! Time to test/modify the code based on your liking and requirement
您应该能够通过访问http://127 . 0 . 0 . 1:5000/在本地访问 web 应用程序
3.根据您希望如何预处理您的输入文本来编辑 model.py ,因为该项目主要关注 Twitter 风格的数据。您也可以更改我最初使用的矢量器 TfidfVectorizer ,但是我在将它部署到 Heroku 时遇到了问题,因为大量的词汇导致了 Heroku 自由层版本的内存过载。使用哈希矢量器将会克服这个限制。
4.将静态文件夹中的logisticregression . pickle文件替换为您自己的模型文件,并在本地/Heroku web 应用程序中测试其相应的输出。请注意,并非所有模型都像逻辑回归一样提供概率得分。我的模型基于 160 万 Twitter 数据集,目前的精度大约是 0.81 (还有很大的提升空间!).
5.通过编辑 css/html 文件,集成 Bootstrap 以及根据您的喜好更改图像/gif/图标,改善网络可视化。我保持了简单的设计,这样任何人都可以很容易地理解代码,并进一步轻松地修改可视化。
结论
我真诚地希望这篇文章能够帮助那些已经在情感分析的基础上构建了自己的自然语言处理(NLP)模型,但是不知道如何可视化地部署它的人(我在学习 NLP 的时候就忽略了这一点)或者那些渴望了解如何免费部署一个基本的、长期运行的 web 应用程序的人**!我还会让我的应用程序在https://cmy-sentiment-analysis.herokuapp.com运行,这样任何人都可以随时访问它!我尽最大努力保持我的代码库相对干净和简单**,并添加了大量评论,因此任何对 Python/web 框架了解有限的人都应该能够很快学会!如果你觉得这篇文章有用,或者对我有任何改进的建议,请在下面评论。干杯!
使用语义搜索构建更智能的聊天机器人
来源: VectorStock
使用语义搜索引擎,你可以不费吹灰之力扩大聊天机器人的覆盖范围。
不太久以前,聊天机器人和助手并不好用。像亚马逊 Alexa 这样的公司是由拥有大量 R&D 预算和专业 ML 和 NLP 团队的公司开发的。
但由于 2017 年推出变压器后 NLP 系统性能的飞跃,加上许多这些模型的开源性质,前景正在迅速改变。像 Rasa 这样的公司使得组织可以轻松地构建复杂的代理,这些代理不仅比早期的代理工作得更好,而且只需要很少的时间和金钱来开发,并且不需要专家来设计。
然而,尽管最近取得了一些进步,但仍有很大的改进空间。在本文中,我们将展示如何通过将客户助手聊天机器人附加到语义搜索后端来扩展它,以处理更广泛的查询。
亚特兰蒂斯迪拜的基本聊天机器人
当迪拜的亚特兰蒂斯酒店于 2008 年开业时,它的水下套房迅速获得了全世界的关注。今天,他们的网站为潜在访问者列出了一百多个常见问题。出于我们的目的,我们将使用 Rasa 构建一个聊天机器人来处理关于这些主题的查询。
你可能想知道 Rasa 聊天机器人提供了什么优势,而不是简单地访问网站的 FAQ 页面。第一个主要优点是,它对查询给出了直接的回答,而不是要求客户浏览一大串问题。
其次,与 Ctrl-F 搜索相比,Rasa 可以更智能地找到内容。凭借 NLP 模型的支持,它可以优雅地处理拼写错误和释义错误。例如,如果我问“允许我的狗吗”,Rasa 给我下面的结果,而 Ctrl-F 搜索“狗”将不会返回任何结果,因为常见问题是你允许在迪拜亚特兰蒂斯养宠物吗?
我们的机器人的源代码可以在github.com/amin3141/zir-rasabot获得,最终版本部署在我们的演示页面。下面的文件提供了使用 Rasa 创作语法的核心知识库实现。
- nlu.yml ,包含常见问题及其变体。
- domain.yml ,包含意图的响应和声明。
- rules.yml ,将 nlu.yml 中定义的意图映射到 domain.yml 中定义的响应。
顾客评论:一个未开发的信息源
随着互联网和在线电子商务的兴起,客户评论是在线景观的普遍元素。评论包含各种各样的信息,但因为它们是以自由形式的文本编写的,并且是用客户自己的话来表达的,所以要访问其中的知识并不容易。
亚特兰蒂斯酒店有数千条评论,其中 326 条包含在 OpinRank 评论数据集中。在其他地方我们展示了语义搜索平台,如 Vectara Neural Search ,如何让组织利用存储为非结构化文本的信息——大规模释放这些数据集中的价值。
Rasa 包含一个称为后备处理器的便利特性,我们将使用它来扩展我们的语义搜索机器人。当机器人没有足够的信心直接处理请求时,它会将请求交给后备处理程序来处理。在这种情况下,我们将针对客户评论语料库运行用户查询,如果结果得分足够高,将显示最多两个匹配项。回退处理程序的源代码可以在 main/actions/actions.py 中找到。第41–79行显示了如何准备语义搜索请求、提交请求以及处理结果。
我们如何确定机器人不够自信?为了本文的目的,我们作弊了:我们直接根据评估数据计算了我们的选择指标 F1 得分,并选择了一个最大化它的阈值。虽然这并不妨碍我们从评估结果中得出结论,但我们必须记住,基线聊天机器人被赋予了不切实际的优势。
我们还使用阈值 0.3 来确定语义搜索回退结果是否足以显示。至关重要的是,这个阈值是从一个不相关的数据集获得的。因此,我们希望我们的指标能够准确反映现实世界的表现。
比较机器人
复杂系统的性能必须进行概率分析,NLP 驱动的聊天机器人也不例外。缺乏严格的评估将会使你很难确信当你扩展你的系统时你正在取得进步。本节的其余部分描述了我们评估聊天机器人的方法。
首先,我们构建了一个包含 63 个问题的评估集。在预订房间之前,我们询问了五位以前住过酒店的人,他们可能有兴趣了解迪拜亚特兰蒂斯酒店的哪些问题。提示中有几个要点需要注意:首先,它介绍了迪拜酒店的位置,以考虑到地理上相关的问题,如*它离海滩有多远?*其次,它还设定了一个目标,这个目标首先符合构建这样一个机器人的现实商业动机,也就是说,帮助潜在客户决定这是否是他们愿意呆的地方。
为了表征机器人的性能,我们从标准的四类答案分类开始,这对于以前使用过 ML 系统的人来说是熟悉的:
- 正确答案:聊天机器人正确回答了这个问题。在我们的评估中,单个评估员做出了决定,尽管如果您的预算允许,使用多个评估员更可靠。
- 误报:聊天机器人回答问题不正确。
- 假阴性:聊天机器人拒绝回答一个合法的问题。当系统回复很抱歉,我没有这方面的任何信息时,这种情况就会出现。
- 真否定:描述聊天机器人避免回答不合理问题的情况,例如,马里纳拉海沟有多深?然而,真正的否定在我们的数据集中并不存在,因为所有的问题都是切题的。
使用这些类,我们将计算精度,这是正确回答的已回答问题的比例,以及真实肯定率,也称为召回率,这是可以正确回答的有效问题的百分比。以下公式表达了这一点:
精确度和真阳性率公式。
为了用一个数字来描述系统的性能,我们将转向 F 值。下面等式中的系数β表示真实阳性率被认为比精度重要β倍。应选择β,以准确反映与假阳性和假阴性结果相关的相对成本。
F 分数的公式
总结和分析
来自默认聊天机器人和启用了回退的聊天机器人的回答被评估并分类如下:
- 默认值:(TP=7,FP=7,TN=0,FN=49)
- 回退:(TP=29,FP=24,TN=0,FN=10)
下图显示了他们在上述指标上的相对表现。
最大的改进是聊天机器人的真实阳性率。在现实问题的评估集上,聊天机器人的正确回答率从 13%上升到了 74%。这也使 F1 得分从 20%提高到 63%。最重要的是,这种改进是通过语义搜索访问现有评论轻松实现的。
精度呢?令人惊讶的是,它似乎也有所改善,从 50%上升到 55%。然而,90%的置信区间清楚地表明,这种差异完全在误差范围内,无法得出任何结论。需要产生更多真阳性和假阳性的更大的问题集。如果没有这个时间间隔,就很难得出这个结论。一个很好的经验法则是,对没有置信区间的统计数据要非常怀疑。
我们已经走到路的尽头了吗?我们能像一位前美国总统曾经做过的那样,宣布“任务完成了吗!”在我们的例子中,就像在他的例子中一样,答案是,没那么快!在本文的最后一部分,我们将讨论在聊天机器人中添加语义搜索时应该考虑的其他一些事情。
总结挑战
顾客评论可能会提到与官方政策不一致的事实。例如,如果顾客询问结账时间,信息性评论可能会说的结账时间是上午 10 点,但我下午 1 点就离开了,这不是问题。因此,机器人需要弄清楚什么时候它在权威地回答,什么时候它在第二手资料中寻找答案。一种方法是以这样的陈述开始搜索结果,比如下面是其他客户不得不说的:
如果顾客问亚特兰蒂斯酒店的房间是否干净呢?管理层会希望机器人成为志愿者吗地毯发臭,墙上有蟑螂在跑!很难想象,即使评论是准确的。定期检查回退处理程序产生的响应是确保这些情况不会发生的一种方法。另一个是从语料库中过滤出负面评论。
注释者之间的协议
当我们评估我们的聊天机器人时,我们将每一个回答分为真或假、肯定或否定。这个任务被称为注释,在我们的例子中,它是由团队中的一个软件工程师执行的。几乎可以肯定的是,如果你让另一个人来注释这些回答,结果将是相似的,但不完全相同。
出于这个原因,包含多个注释者并跟踪它们之间的一致程度是一个好的实践。注释者的分歧也应该反映在我们度量的置信区间中,但是这是另一篇文章的主题。
资源和引用
- 启用了回退功能的 Hotel Atlantis 聊天机器人。
- 所有 63 个问题的评估结果
- 关键词搜索的高成本包括一个教程,展示如何将客户评论上传到 Vectara Neural Search。
- Rasa 利用最新的语言理解技术构建对话系统。
- 甘乃山,K. A .和翟春祥,“基于观点的实体排名”,信息检索,2011 年。
阿明·艾哈迈德是 Vectara 的联合创始人。聊天机器人是由 Basit Anwer 开发的。
使用 Gretel.ai 和 Apache Airflow 构建合成数据管道
现实世界中的数据科学
在这篇博文中,我们使用 Gretel 的合成数据 API和Apache air flow构建了一个从 PostgreSQL 数据库生成合成数据的 ETL 管道
照片由seli̇m·阿尔达·埃尔伊尔马兹在 Unsplash 上拍摄
嗨,伙计们,我叫德鲁,我是一名软件工程师,在 Gretel.ai 。我最近一直在思考将 Gretel API 集成到现有工具中的模式,这样就很容易建立数据管道,安全和客户隐私是第一位的特性,而不仅仅是事后的想法或检查框。
数据工程师中流行的一个数据工程工具是 Apache Airflow。这也正好与 Gretel 的工作很好。在这篇博文中,我们将向您展示如何使用 Airflow、Gretel 和 PostgreSQL 构建一个合成数据管道。让我们跳进来吧!
什么是气流?
Airflow 是一个常用于构建数据管道的工作流自动化工具。它使数据工程师或数据科学家能够使用 Python 和其他熟悉的构造以编程方式定义和部署这些管道。气流的核心是 DAG 或有向无环图的概念。气流 DAG 提供了用于定义管道组件、它们的依赖性和执行顺序的模型和一组 API。
您可能会发现气流管道将数据从产品数据库复制到数据仓库。其他管道可能会执行查询,将规范化的数据连接到适合分析或建模的单个数据集。另一个管道可能发布汇总关键业务指标的每日报告。这些用例有一个共同的主题:协调跨系统的数据移动。这是气流闪耀的地方。
利用 Airflow 及其丰富的集成生态系统,数据工程师和科学家可以将任意数量的不同工具或服务整合到一个易于维护和操作的统一管道中。了解了这些集成功能后,我们现在将开始讨论如何将 Gretel 集成到气流管道中,以改善常见的数据操作工作流。
格雷特尔是怎样融入的?
在 Gretel,我们的使命是让数据更容易、更安全地使用。在与客户交谈时,我们经常听到的一个痛点是让数据科学家访问敏感数据所需的时间和精力。使用 Gretel Synthetics ,我们可以通过生成数据集的合成副本来降低使用敏感数据的风险。通过将 Gretel 与 Airflow 集成,可以创建自助管道,使数据科学家可以轻松快速地获得他们需要的数据,而不需要数据工程师来处理每个新的数据请求。
为了演示这些功能,我们将构建一个 ETL 管道,从数据库中提取用户活动特征,生成数据集的合成版本,并将数据集保存到 S3。随着合成数据集保存在 S3,它可以被数据科学家用于下游建模或分析,而不损害客户隐私。
首先,让我们来鸟瞰一下管道。该图中的每个节点代表一个管道步骤,或气流术语中的“任务”。
气流上的格雷特合成材料管道示例。(图片由作者提供)
我们可以将管道分成 3 个阶段,类似于 ETL 管道:
- 提取—
extract_features
任务将查询数据库,并将数据转换为一组数据科学家可以用来构建模型的特征。 - 合成—
generate_synthetic_features
将提取的特征作为输入,训练一个合成模型,然后使用 Gretel APIs 和云服务生成一组合成的特征。 - 加载——
upload_synthetic_features
将综合特征集保存到 S3,在那里它可以被摄取到任何下游模型或分析中。
在接下来的几节中,我们将更详细地探讨这三个步骤。如果你想了解每个代码示例,你可以去grete lai/Gretel-air flow-pipelines下载这篇博文中用到的所有代码。repo 还包含启动 Airflow 实例和端到端运行管道的说明。
此外,在我们剖析每个组件之前,查看完整的气流管道可能会有所帮助。以下部分中的代码片段摘自链接用户预订管道。
提取特征
第一个任务extract_features
负责从源数据库中提取原始数据,并将其转换成一组特征。这是一个常见的特征工程问题,你可能会在任何机器学习或分析管道中发现。
在我们的示例管道中,我们将提供一个 PostgreSQL 数据库,并加载来自 Airbnb Kaggle 竞赛的预订数据。
这个数据集包含两个表,Users
和Sessions
。Sessions
包含一个外键引用user_id
。利用这种关系,我们将创建一组包含由用户聚合的各种预订指标的特性。下图显示了用于构建要素的 SQL 查询。
然后从我们的气流管道执行 SQL 查询,并使用以下任务定义将其写入中间 S3 位置
任务的输入sql_file
决定了在数据库上运行什么样的查询。该查询将被读入任务,然后对数据库执行。然后,查询结果将被写入 S3,远程文件密钥将作为任务的输出返回。
下面的屏幕截图显示了上面提取查询的示例结果集。我们将在下一节描述如何创建该数据集的合成版本。
查询结果预览。(图片由作者提供)
使用 Gretel APIs 合成特征
为了生成每个特征的合成版本,我们必须首先训练一个合成模型,然后运行该模型来生成合成记录。Gretel 有一组 Python SDKs,可以很容易地集成到 Airflow 任务中。
除了 Python 客户端 SDK,我们还创建了一个 Gretel Airflow Hook 来管理 Gretel API 连接和秘密。设置好 Gretel 气流连接后,连接到 Gretel API 就像
有关如何配置气流连接的更多信息,请参考我们的 Github 知识库自述文件。
上例中的project
变量可以用作使用 Gretel 的 API 训练和运行合成模型的主要入口点。更多细节可以查看我们的 Python API 文档,https://Python . docs . Gretel . ai/en/stable/projects/projects . html。
回到预订管道,我们现在来回顾一下generate_synthetic_features
任务。此步骤负责使用前一任务中提取的特征来训练合成模型。
查看方法签名,您会看到它需要一个路径,data_source
。该值指向上一步中提取的 S3 要素。在后面的部分中,我们将介绍所有这些输入和输出是如何连接在一起的。
当使用project.create_model_obj
创建模型时,model_config
参数代表用于生成模型的合成模型配置。在这个管道中,我们使用我们的默认模型配置,但是许多其他的配置选项也是可用的。
模型配置好之后,我们调用model.submit_cloud()
。这将使用 Gretel Cloud 提交用于训练和记录生成的模型。调用poll(model)
将阻塞任务,直到模型完成训练。
现在模型已经训练好了,我们将使用get_artifact_link
返回一个链接来下载生成的合成特征。
合成集特征的数据预览。(图片由作者提供)
这个工件链接将被用作最终upload_synthetic_features
步骤的输入。
加载合成要素
原始特征已经被提取,并且已经创建了合成版本。现在是上传合成特性的时候了,这样下游消费者就可以访问它们了。在本例中,我们将使用 S3 桶作为数据集的最终目的地。
这项任务非常简单。data_set
输入值包含一个签名的 HTTP 链接,用于从 Gretel 的 API 下载合成数据集。该任务将把该文件读入 Airflow worker,然后使用已经配置好的 S3 钩子把合成特征文件上传到 S3 桶,下游消费者或模型可以访问它。
协调管道
在过去的三个部分中,我们已经浏览了提取、合成和加载数据集所需的所有代码。最后一步是将这些任务捆绑到一个单独的气流管道中。
如果你还记得这篇文章的开头,我们简要地提到了 DAG 的概念。使用 Airflow 的 TaskFlow API,我们可以将这三个 Python 方法组合成一个 DAG,该 DAG 定义了输入、输出以及每个步骤的运行顺序。
如果您遵循这些方法调用的路径,您最终会得到一个看起来像我们的原始特性管道的图。
气流上的格莱特合成纤维管道。(图片由作者提供)
如果你想运行这个管道,并看到它的运行,那就去 Github 仓库的看看吧。在那里,您可以找到关于如何启动一个 Airflow 实例并端到端运行管道的说明。
包装东西
如果您已经做到了这一步,那么您已经看到了如何将 Gretel 集成到基于气流的数据管道中。通过结合 Gretel 的开发人员友好的 API 和 Airflow 强大的钩子和操作符系统,很容易构建 ETL 管道,使数据更容易访问,使用起来更安全。
我们还讨论了一个常见的特性工程用例,其中敏感数据可能不容易访问。通过生成数据集的合成版本,我们降低了暴露任何敏感数据的风险,但仍然保留了数据集的效用,同时使需要它的人可以快速获得它。
从更抽象的角度来考虑特性管道,我们现在有了一个可以重新用于任何数量的新 SQL 查询的模式。通过部署新版本的管道,并替换初始 SQL 查询,我们可以用保护客户隐私的合成数据集来处理任何潜在的敏感查询。唯一需要更改的代码行是 sql 文件的路径。不需要复杂的数据工程。
感谢阅读
如果您有任何问题或意见,请发送电子邮件至 hi@gretel.ai 或加入我们的 Slack 。我们希望了解您如何使用 Airflow,以及我们如何才能最好地与您现有的数据管道集成。
用 Python 构建文本推荐系统
使用 NLP 语义相似度来提供最准确的推荐
自然语言处理是机器学习中最令人兴奋的领域之一。它使我们的计算机能够理解非常密集的语料库,分析它们,并为我们提供我们正在寻找的信息。
在本文中,我们将创建一个推荐系统,其行为类似于一个垂直搜索引擎*【3】。它允许在非常有限的与一个主题高度相关的文档中搜索文档。为了充分利用 NLP 的能力,我们将把搜索方法与语义相似性结合起来。*
本文包括不同 NLP 模型的数据集、理论、代码和结果。
为什么要用机器学习?
- 机器学习和深度学习擅长提供捕捉单词和文档语义的文本数据的表示,允许机器说出哪些单词和文档语义相似。深度学习的使用能够为其最终用户提供更多相关结果,提高用户满意度和产品功效。在本文中,我们将致力于一个为您的数据量身定制的解决方案,并且稍后可以将您的数据与用户查询进行比较,以提供排名良好的结果。
- 对于大多数常见的编程语言,如 Python,许多开源库提供了工具,可以在您自己的数据上创建和训练非常简单复杂的机器学习模型。在本文中,我们将看到在您自己的机器上构建和训练模型有多快。
用例
想象一下,你想看一部电影,但你已经看完了遗愿清单上的所有电影。今天你想看一部电影,里面一个美丽的女人卷入了一场犯罪。我们将建立的推荐系统会将您理想的电影描述与电影描述数据库进行匹配,并推荐符合您描述的前三部电影。
这非常简单,要构建这个管道,您需要:
- 包含要推荐的文本项集合的数据集。
- 一种句子清洁算法
- 匹配算法。
我们来编码吧!
您可以在 jupyter 笔记本中访问本文的所有代码。
j .凯利·布里托
准备数据
作为查找表的数据集
对于这个玩具实验,我们使用电影数据集https://www.kaggle.com/rounakbanik/the-movies-dataset。
它包含 2017 年 7 月之前发布的 44,512 部电影的元数据。幸运的是,我们不会全部观看,因为我们会选择符合我们确切愿望的一个。
在我们的实验中,我们将只使用表“movies_metadata.csv ”,它包含的属性有:预算、流派、网页链接、 原标题、描述概述 、上映日期、口语、IMDb 平均投票、…。
我们的推荐系统将使用电影描述概述句子,并应用机器学习模型将每个句子表示为数字特征向量。在将 ML 模型应用于每个句子之后,我们可以连接这些特征向量来创建代表整个数据集的嵌入矩阵。这个矩阵非常重要,它将是我们对系统进行的每个查询的查找表。
作者图片
假设我们有 100 个电影描述句子,我们的嵌入向量大小是 300,那么我们的嵌入矩阵大小将是(100×300)。当用户输入一个句子时,我们使用相同的模型将其查询句子嵌入到 300 维向量中,并计算 100 行中的每一行与嵌入的查询向量之间的余弦距离。
加载数据集
下载。csv 文件,并将其作为数据框加载到 python 脚本或笔记本中。
干净的句子
我们会做基本的预处理。我们希望给模型一个统一的文本,所以我们在将句子嵌入向量之前对它们进行清理。这将有助于模型关注内容而不是格式来找到数据中的相关模式。
让我们回顾一下下面的清洁方法。
- 删除非字母数字字符/标点符号,
- 删除太长和太短的句子,
- 删除停用词,
- lemmatize,
- 标记化
我们使用正则表达式模式匹配从电影描述中删除所有非字母数字字符。
我们创建自己的记号赋予器。记号赋予器将一个字符串转换成一个字符串列表,其中每个元素是一个单词。
*word_tokenizer(‘the beautiful tree has lost its leaves’)
>>> [‘the’, ‘beautiful’, ‘tree’, ‘has’, ‘lost’, ‘its’, ‘leaves’]*
我们使用一个词条解释器将一个单词转换成通用形式:
*from nltk.stem import WordNetLemmatizer
stemmer = WordNetLemmatizer()
[stemmer.lemmatize(w) for w in word_tokenize(sentence)]
>>> ['the', 'beautiful', 'tree', 'ha', 'lost', 'his', 'leaf']*
我们通过使用最小单词和最大单词进行过滤,从数据集中删除太短和太长的句子。我们去掉了对提取给定句子的特殊性没有帮助的常用词(停用词)。
清洁的结果
我们将“句子”列转换为两列:
- clean_sentence 这里的句子主要是字母数字文本。
- tok_lem_sentence 其中数据被词汇化和标记化。
加载、训练、预测
现在,我们的数据集已准备好进行处理,我们可以比较提供不同折衷方案的不同模型:
- 基准/基本 TF-IDF
- ***Word2Vec,*一个简单的前馈网络
- 非常灵活和强大的 NLP 库
- 变形金刚,最先进的深度学习模型。
我在下面介绍一个函数,在给定向量之间的余弦距离的情况下,我将使用该函数对最佳推荐进行排序。
你可以注意到在 l.11 中,我们在距离矩阵上使用了平均值。距离矩阵的形状是(查询句子中的字数,我们的词汇表中的句子数)。我们计算从查询的每个单词到数据库的每个句子的距离,并取整个查询的平均值。然后我们可以选择与查询距离最小的三个句子。
基准模型,TF-IDF
什么是 TF-IDF?
文本语料库通常包含经常出现的单词,并且不包含任何有用的歧视性信息。Tf-idf 旨在降低这些频繁出现的单词在特征向量中的权重。它可以被定义为术语频率(一个词在给定文档中的频率)和逆文档频率(该词在所有文档中的出现次数)的乘积[1]。术语频率/文档频率测量术语在给定文档中的相关性。在我们的例子中,一个文档就是一个句子。
应用 TF-IDF
一旦我们在 Tf-idf 模型上拟合我们的数据,我们可以为每个电影描述生成嵌入的 22,180 维向量。这些特征存储在特征矩阵 tfidf_mat 中,其中每一行都是嵌入到特征向量中的电影描述记录。
当我们从用户输入中获得一个查询时,我们将把它嵌入到相同的向量空间中,并且我们将逐个比较查询句子特征 embed_query 和嵌入矩阵 tfidf_mat 的句子向量。
从距离矩阵中找到最佳索引的函数取每个嵌入句子的余弦距离的平均值,并对结果进行排序。暂时不要注意掩蔽参数,我们将把它用于另一个模型。
这个模型使用起来非常简单,只需要几行代码就可以完成,训练也非常快。
关于疑问句:‘一个有美女的犯罪故事’,
前 3 名结果
-一个美丽的吸血鬼把一个犯罪头目变成了夜行动物。无辜的血
-一个吸血鬼引诱年轻漂亮的女人到他在欧洲的城堡。吸血鬼安魂曲
-一个年轻女子在被有组织犯罪控制的墨西哥坚持梦想成为选美皇后的故事。巴拉小姐。
你的数据模型,Word2Vec
Word2Vec 是一个强大而高效的算法,可以捕捉你语料库中单词的语义。Word2vec 在训练期间采用包含许多文档/句子的语料库,并输出一系列向量,文本中的每个单词一个向量。单词向量包含该单词的语义,这意味着在向量空间中接近的两个单词具有相似的含义。国王和王后就像蛋糕和咖啡一样亲密。例如,Word2Vec 可以很容易地用于查找同义词。在训练期间,神经网络根据从训练数据集中推断的出现概率对每个词向量进行加权。这个概率是如何计算的取决于你选择的架构(连续单词包或跳格)。最后,word2vec 模型实际上是一个非常简单的 2 层神经网络,但我们不会关心输出,我们将提取信息编码的隐藏状态[3]。word2vec 的优势在于它采用高维稀疏单词表示(如 tf-idf 或 hot encoded vectors ),并将其映射为密集表示,希望在更小的维度中。
应用 word2vec
我们使用 gensim 库在我们的语料库数据上训练一个 word2vec 模型。我们首先需要提供词汇表(我们要向量化的单词列表),然后在几个时期内训练模型。默认情况下,模型训练 CBOW。
Word2Vec 的主要缺点是它不能为最初不在词汇表使用训练中的单词生成向量。这就是为什么我们需要提供一个 utils 函数 is_word_in_model 来从查询语句中删除在训练集中看不到的单词。
我们使用他们的库函数 n_similarity 来有效地计算查询语句和数据集语句之间的距离。
前 3 名结果
- A tragic love story set in contemporary Shanghai. The film stars Zhou Xun in a dual role as two different women and Jia Hongsheng as a man obsessed with finding a woman from his past. 苏州河
-一个发光的球体用一系列黑暗幻想、色情和恐怖的故事恐吓一个年轻的女孩。重金属。
-弗里茨·兰的心理惊悚片讲述了一个女人嫁给了一个有致命嗜好的陌生人,通过他们的爱,他试图摆脱他的强迫症行为。门外的秘密
很好的妥协模式,斯帕西
spaCy 是一个 python 开源库,包含许多针对各种语言的预先计算的模型(参见 64+语言列表这里)。因为我们需要加载与每个单词相关的向量,所以我们使用一个经过训练的管道来访问特征向量,即 en_core_web_lg 。他们将其 NN 称为 Tok2Vec,我们可以使用包含 685k 个关键字的预训练权重作为在网页语料库上训练的 685k 个维度 300 的唯一向量。SpaCy 有自己的深度学习库和模型。你可以在这里阅读更多关于他们默认的 CNN+散列嵌入模型。他们的管道包括记号化器、词汇化器和单词级矢量化,所以我们只需要提供字符串形式的句子。
我们使用掩码 l.12,以防该单词在预训练的语料库中没有单词。
前 3 名结果:
就算预计 spaCy 比 TF-IDF 更厉害,对于这句话,给出的结果也和 TF-IDF 一样。
最强大的变形金刚
如果我们想要一个鲁棒且准确的方法,我们可以使用深度学习。幸运的是,许多图书馆已经发布了他们自己的预训练权重,我们不需要花几个月的时间在整个互联网上训练一个非常深入的模型。
我们将使用伯特建筑。成本高于以前的模型,但对环境的理解也更加敏锐。
变形金刚库
’ SentenceTransformers '团队开发了他们自己的高级管道,以方便在 Python 中使用变压器。你可以点击查看他们的车型和推荐列表。我个人选择了满足 高质量的快速模型**-MiniLM-L6-v2。**
前 3 名结果
-一个年轻女子在被有组织犯罪控制的墨西哥坚持梦想成为选美皇后的故事。巴拉小姐。
-在一名年轻女子在她的邻居中被可怕地谋杀后,一名生活在纽约市的自决女子-好像是在测试她自身安全的极限-将自己推进了一场不可思议的冒险性关系。很快,她变得越来越警惕与她接触的每个男人的动机,以及她自己的动机。在切口处。
-一个奋斗中的美国艺术家和一个美丽的中国香港妓女之间的爱情故事。苏丝黄的世界
与以前的模型相比,我们可以看到结果的改进。
用 HuggingFace 编写自己的 BERT 管道
SentenceTransformer 在后端使用 HuggingFace 架构。HuggingFace 作为 NLP 技术的开源提供商领导着这项研究。他们免费公开模型、数据集和代码库。任何人都可以训练他们的模型并将结果推送到他们的数据库中。
我们将使用标记化器(AutoTokenizer)和模型(AutoModel)来检索句子-transformer/ 释义-MiniLM-L6-v2 。
我们可以选择在 CPU 或 GPU 上训练,我们使用 fit_transform 使用一批数据来生成我们的嵌入矩阵,以避免内存过载。再次在转换方法中,我们使用 mean_pooling 函数来推断每个单词的向量,并对每个句子进行平均。这种汇集比以前更复杂,因为 BERT 中的注意机制使用掩码,我们在平均之前将它们应用于结果。
代码比我们使用 SentenceTransformer 时稍长,但我们也有更多的灵活性。我们需要设计自己的推断方法也更加透明
训练和预测(CPU 或 GPU)
训练需要时间,所以如果你有 GPU,用它来加快你的训练。对于这个数据集,在我的 16Gb 8 CPUs 本地计算机上,对 20,000 个句子行的训练在 CPU 上花费了12 分钟,而当我使用具有相同训练配置的本地 GPU (GeForce MX150)时,训练仅花费了6 分钟*。***
示例查询:
查询:‘一只狗在和他的朋友玩’
伯特模型:“一个男人拯救了一只德国牧羊犬,两人如何成为好朋友的故事。”[我的狗郁金香]
查询:“一部欧洲英雄电影”
伯特模型:“在一个反乌托邦的欧洲,一名警察调查一名连环杀人案嫌犯,使用了他现在已经名誉扫地的前导师写的有争议的方法。”[Forbrydelsens 元素]
(我们可以断定它不存在于数据库中)
查询:《一个女服务员的故事》
伯特模特:“一名女服务员不顾一切地想要实现她当餐馆老板的梦想,踏上了将青蛙王子变回人类的旅程,但是在她吻了他之后,她不得不面对同样的问题。”[公主和青蛙]
结论
一旦我们加载并矢量化了初始数据集,我们就可以使用一个新句子作为查询,并从数据集中检索与该查询句子匹配的前 3 个最接近的项目。
为此,我们使用了简单的 TF-IDF 模型,该模型使用单词和句子中的频率来创建向量。我们使用了 Word2Vec 模型,一个简单的神经网络。我们使用了 spaCy ,它可以处理和计算许多不同语言的向量,具有最先进的性能。
最后,我们使用 transformer 模型来利用最新的深度学习方法进行矢量化。深度学习技术可以实现最好的(主观上)检索结果,但它们较慢。选择最适合你权衡的方法!
资源
[1] Python 机器学习,Sebastian Raschka,Packt Edition(https://www . packtpub . com/product/Python-Machine-Learning-third-Edition/9781789955750)
[2]http://mccormickml . com/2016/04/19/word 2 vec-Tutorial-The-skip-gram-model/,http://mccormickml . com/assets/word 2 vec/Alex _ Minnaar _ word 2 vec _ Tutorial _ Part _ II _ The _ Continuous _ Bag-of-Words _ model . pdf
[3] 用于搜索的深度学习,托马索·特奥菲利,曼宁出版。