作者档案: 管理员

一个优秀的数据团队由什么组成?

数据团队很难招募。工程师的供应量低,需求量大,如果没有耗时的电话/编码屏幕,甚至没有FAANG,就很难审查简历。’的资源,很难找到像您一样对产品充满热情的人。作为招聘经理,您可能有幸负担得起专业招聘人员的服务。但是,招聘人员通常会向您发送完全不合适的候选人。

A very friendly recruiter I know 在 NYC 和 I had coffee 的 其他 day 至 discuss 的se 在dustry 问题s. We agreed 那 它 would 是 采用ful 如果 we 定义的 什么 makes 向上 a 格蕾at 数据 team 和 什么 的 roles actually mean.

我应该首先雇用谁?他们如何一起工作?

  • 数据分析师
    • 雇用数据团队的目标可能是业务洞察力,并在某种程度上使您的行动主要由数据(而非直觉)驱动。为此,您需要一个有能力的数据分析师。值得庆幸的是,数据分析师的人数很多。渴望挖掘洞察力并具有定量或半定量(例如Econ)背景的新毕业生不应该’太难找了。在高端,您可以找到具有SQL经验的人以及相对较新的BI工具(如Looker)。如果您有预算,则可以使用即插即用的流水线工具(例如细分)解决75%的工程任务。最标准的业务见解– “昨天/上个月发生了什么?”, “what’我的客户群中服务不足的人群?”没有昂贵的数据科学家就可以回答。
  • 数据工程师
    • 在某些时候,您的数据库和查询将变得太慢。您’ll还想抓取数据源或使用没有人为Segment中的连接器建立过的API。也许你’我想要一些定制的销售线索评分’一堆安全问题’您希望每天早晨刷新一些庞大的查询,并在Slack中通知您。没有编程背景,您的数据分析师会感到不胜其烦。这是您需要雇用数据工程师的时候。他们的专业知识真正在于使您的数据集达到可分析的地步。如果您的表每月收到5000万个事件,那么查询将在一夜之间开始花费数小时,并且表甚至可能被锁定。数据工程师可以缓解这种情况– 的y 将能够优化数据库的索引’用于快速查找的s表,创建有用的聚合的物化视图,这些聚合每天早晨刷新,将自定义API连接到您的数据仓库,并且通常超出即插即用工具所涵盖的范围。 
  • 数据科学家
    • 现在你’重新获得标准的业务见解,并从有趣的来源中大规模获取它们’几乎肯定会对AI的警笛声感到好奇。如果您可以预测哪个客户会流失/转换,该怎么办?如果您可以按行为将客户群聚在一起怎么办?称职的数据科学家有可能提供这种更深入的了解。他们将使用Python中的机器学习库来尝试自动对您的客户和系统中的操作进行分类。他们可以预测未来(以一定的准确性),并告诉您有关数据的故事。这将涉及使用数据工程师提供的大型数据集。一旦这些见解浮出水面,他们将获得训练有素的模型,可以将其保存到磁盘并进行刷新。但是,如果需要每天刷新一次,并将这些见解添加到数据分析师甚至销售员可以读取的表中,该怎么办?然后,您需要返回到数据工程师,并让他们设置一个后端系统来执行此操作。
  • 数据科学工程师,机器学习工程师
    • 有时,您的(可能是较老的)数据工程师将100%专注于管道和数据库管理员,并且在实施数据科学家想出的基于Python的模型方面没有特别的经验。对于此问题,您需要一名数据科学工程师或机器学习工程师。他们的专长是部署,扩展和刷新数据科学家提出的模型。数据科学家应该完全专注于概率,调整模型参数和置信度分数;您的数据分析师应该专注于更高层次的叙述,而您的DS / ML工程师现在可以采用该模型,并确保该模型可以快速提供您的见解,并提供干净,新鲜,正确的数据。
  • 可视化工程师
    • 如果Looker没有,该怎么办’没有您想要的图表?如果您需要可视化网络怎么办?如果您的数据有16个维度并且您’是否已用完散点图中的所有颜色,大小和形状选项?然后,您需要可视化工程师的非常专门的角色来构建自定义可视化并想出更好的方法来揭示数据分析师难以解决的见解。
  • 商业智能工程师
    • 这是一个模棱两可的标题–他们可能是数据科学工程师或数据工程师。

的角色

标题 工作职责 工具/技术
数据分析师  基本业务见​​解 外观 / Tableau,SQL,Excel,Redash
数据科学家 更复杂的业务预测 Jupyter笔记本,Python,Scikit-Learn,Numpy,Scipy,Statsmodels
数据工程师 得到“Big 数据”到可以分析以及连接自定义数据源的地步 SQL,Python,Scrapy,Spacy,Selenium,Kafka,Airflow,Luigi,Spark,AWS,Redshift
数据科学工程师或机器学习工程师 实施数据科学家’s models 在 scale SQL,Python,Scikit-Learn,Numpy,Scipy,AWS,TensorFlow
可视化工程师(稀有) 制作精美的图形以增强每个人’s work 外观 / Tableau,Javascript,D3.js,Highcharts,HTML

但是,为什么每个人都只专注于数据科学?

数据科学是一个流行词,有人用它来表示适合数据工程和分析交叉领域的任何人。公司犯下的最大错误之一就是雇用了太多的数据科学家而没有足够的数据工程师。最近,许多前数学家,化学家,统计学家和其他数量级的毕业生发现,数据科学家正在变得更容易招聘,他们可以轻松地重塑自己的形象或参加3个月的Bootcamp并担任初级职位。但是,他们的模型和洞察力可能会受到限制,因为他们没有’不知道如何扩展/部署它们;他们将花费大量时间来清理数据集,而不是专注于隐藏在其中的消息和预测。当然,作为一个现在主要专注于数据工程的人,我有偏见,但是我想说,每个数据科学家都应与至少一名数据工程师配对。我实际上从数据科学专业转到数据工程专业的原因确实是出于我自己工作的需要。

我希望本指南今天能成功解释’的数据团队。如果您有任何改进建议,请发表评论或给我发送电子邮件。

开源DIMA–方便的数据库监视工具

框架上的数据

在像 框架,我们将收到大量数据-每月超过6700万个事件。高效的分析对于保持市场领导者地位至关重要,我们使用大量工具:

  • GUI之类的 外观Redash and 续集
  • 内部分析和查询并行化微服务
  • 我们为垃圾邮件/入侵检测和销售线索发现而构建的定制AI Slackbots

这意味着我们的数据仓库经常受到大量查询的攻击,无论是在Cron计划中还是在员工探索我们的数据集方面都如此。

数量问题

管理如此大量的查询可能很困难。

  • PostgreSQL表可以锁定-例如,在其他人查询表时尝试交换/删除表将导致它们锁定。理想情况下,分析表仅应进行增量更新,但有时设计限制会阻止这种情况。
  • SQL GUI可能会随机超时,这对快速检查数据库以查看它们是否仍在运行很有用。
  • 使用 a combination 的 screen and psql to 跑 queries 在 的 background 要求s monitoring. Dima 是 格蕾at 对于 那.
  • 数百万行表上没有LIMIT的意外SELECT可能会使SQL GUI崩溃。
  • Sometimes a big 询问 just 是n’t 什么 您 想ed. 伪装l没有取消按钮,而托管的GUI(如Redash和Looker)具有“取消”按钮,这些按钮对于长时间运行的查询通常无响应。

迪玛

为了帮助解决此问题,我构建了一个名为dima的小型命令行工具。它最初代表“数据库完整性监控”&分析”,但现在只是“ dima”。它非常简单,而且非常有用,因此我可以将其开源。

Dima 是 a 蟒蛇 脚本 那 basically 让s 您 quickly summarize 要么 在spect 的 pg_stat_activity internal table 在 Postgres via 的 psycopg2 LIBrary. If 您 想 至 杀 a 询问 它 将 呼叫 pg_terminate on 的 PID.

查看 //github.com/Frameio/homebrew-dima.

安装 使用 pip 安装 dima-db or 酿造 tap Frameio/homebrew-dima && 酿造 安装 dima

指令

dima —正在运行的查询摘要

dima show [PID] -检查特定的正在运行的查询

dima R M [-f] Some PID 要么 键word —杀死查询/查询

我们如何在Frame.io中分配注册

为60万用户分配800M点击

在 框架 we 采用 分割 支持我们的应用使用情况分析。可以通过使用事件名称(例如“注册“ 要么 ”观看视频”。

此数据对于我们的A / B测试和分析至关重要。与细分市场与以下服务的出色集成相结合 明比特,我们可以使用公司信息来丰富个人资料,然后跟踪用户首次访问我们的任何服务。这些数据使我们能够确定哪些博客作者吸引了最高的LTV客户,哪些YouTube潜在受众群体产生了最少的粘性用户,等等。

我们利用各种不同的增长渠道滴灌电子邮件活动,Facebook,YouTube,Twitter,Google AdWords,它们都有各自独立的平台,其中一些并不同步到我们的数据仓库中。需要一个系统来均匀化此信息,以便我们可以在一个地方分析客户,渠道,活动和媒体。

归因实际上是从360度角度了解公司的市场契合度,以及其向正确的受众简要说明其服务的能力。

规划归因系统

Conceptually 在tribution 是 quite simple — just 找 的 first 结果 在 您r 数据base 对于 的 采用r’s ID 和 extract a UTM right? However, 的re’s a 至n 的 considerations 之前 您 can 得到 至 那 single 行 的 数据 那 shows where a 采用r came 从:

  • 即使建立了很好的索引,每天仍要在数百万行中搜索数千个用户,并维护这些行后面的分区和索引可能对数据库造成很大的负担。
  • 用户首次访问该网站时,他们没有user_ids,而是由Segment分配的onymous_id。用户ID仅在用户创建帐户后才与该用户相关联,并且“ iy”呼叫同时使用anonymous_id和user_id。有时,我们会发现一年多以前用户的anonymous_id。拥有用户的全局ID(从系统分配)后,我们必须在分配ID之前回填所有匿名会话。
  • 在注册之前,我们必须对每组用户操作进行会话,并汇总有关他们的第一个/最后一个会话的属性。会话化是将离散的用户事件聚合到页面加载过程中的过程,间隔不超过20分钟。这使我们能够做一些事情,例如分析访问的整体意图并进行批量归因。重新会话涉及巨大的嵌套窗口函数和别名表,因为同一用户经常要合并几个历史的匿名ID。
  • 我们将希望维护一些快速查找表以使其有用。-用户会话计数,有用的会话,也许还有一些汇总,以了解我们在可视化工具(如可视化工具)中的工作方式 外观.
  • 另请注意,细分实际上具有本地 归因 您可以安装带有摘要的系统;但在安装之前无法回溯。,我们的数据可以追溯到2014年。

实施阶段

系统设计基于以下8个查询组/阶段:

  1. 在现有的会话化数据中查找最新的时间戳
    1. 从细分跟踪表中获取所有最新访问数据
    2. 将此数据与最近的每月分区合并,并使用一些代码来检查列是否仍然相同(可以添加新字段)。
  2. 会话化最近的分区(最近24小时可能有重叠,因此请确保覆盖了空白)
    1. 用任何新标识的匿名/用户对更新别名表。
    2. 返回所有历史会话并重新别名-即将匿名ID替换为任何新标识的user_id。
    3. 重新会话化所有历史会话,因为相邻的会话在历史上可能具有不同的匿名ID,但现在具有相同的user_id
  3. 添加额外的一列以指示用户是否注册了会话
    1. 将生成的会话表合并到单个all_sessions表中
    2. 为有用的会话创建查找表-这是第一个会话,并且仅针对每个用户的注册会话
  4. 创建一个有用的归因表,其中包含预先提取的UTM参数和会话计数
  5. 重新索引所有表,并检查分区顺序是否正确(尤其是在新的月份间隔内)。

表结构

表/图式:

  • 混叠
  • 会议
    • 归因
    • all_sessions
    • 有用的会话
  • session_stages
    • all_tracks_2018_01
    • all_tracks_2018_01_aliased
    • all_tracks_2018_01_re_merged
    • all_tracks_2018_01_signup
    • …etc
  • 分割
    • 应用程式_tracks_2018_01
    • 应用程式_tracks_2018_02
    • 应用程式_tracks_2018_03
    • …etc

最终的sessions.attribution表中的列(许多只是快速查找,易于聚合,并且该表已建立大量索引):

  • alias_id
  • session_count_before_signup
  • signup_timestamp
  • blog_url
  • first_page_ever_visited
  • 首次接触(即与任何frame.io属性的首次互动)
    • 时间戳记
    • 来源,广告系列,媒体,引荐来源
  • 最后一次接触(即注册前的最后一次互动)
    • 时间戳记
    • 来源,广告系列,媒体,引荐来源
  • 首次归属接触(如上所述,但带有付费推荐人)
    • 时间戳记
    • 来源,广告系列,媒体,引荐来源
  • 最后归属的联系方式(如上所述,但带有付费引荐来源)
    • 时间戳记
    • 来源,广告系列,媒体,引荐来源

部署和监控

该系统花了大约1.5个月的时间才能正常运行,并且需要大约800行代码(Python,SQL,Shell和YAML)。

像AWS,Google Cloud和Azure这样的云计算生态系统使部署这样的微服务变得非常简单。该代码是Dockerized(在 高山的)并部署在 ECS Fargate 簇。新的版本由处理 代码管道,它监视Github仓库的归属。基础数据库是 极光Postgres.

该系统每天早上大约需要运行4个小时,并且可能会遇到诸如底层表缓慢或不可用之类的困难。为了减轻这种情况,每个查询都有一个2小时的重试系统。

性能已登录 AWS Cloudwatch,已同步到 数据狗。如果重试后任何查询完全失败,则 寻呼机 ping已发送到我的手机。

结果

  • 出色的统计信息-71%的用户在第一次访问时就注册了!
  • 对Frame.io采取了8亿个操作(我们的细分跟踪表分区的行数-),我们现在有60万用户。
  • 我们不再需要深入研究特定的平台(例如Facebook Business,Google Analytics(分析)),而是将所有分析都集中在一个地方并可以在Looker中将其可视化!
  • 我们可以通过简单的SQL分组法轻松地计算每个广告系列或频道的平均LTV。
  • 我们可以评估来源的粘性-例如我们的YouTube广告能为我们带来长期或快速流失的客户吗?
  • 作为直觉检查,我们要求用户报告他们听说过Frame.io的位置(直接访问的比例为50%,YouTube的比例为14%,Facebook的比例为10%),这些数字与我们的“首次触摸”列完全匹配。

我们从这里去哪里?

  • 此归因系统只是实际分析背后的管道。当我们不得不做出更多的哲学决定时,这将变得更加困难。我们如何确定如何归因于“多点触控”用户?例如。如果用户在一篇博客文章上具有第一接触,而几个月后在另一文章上具有最后接触,那么谁能得到功劳呢?
  • 我们目前正在密切监视性能,该过程大约需要4个小时。但是,我们的流量每个月都在以惊人的速度增长-这种持续时间将持续多长时间?值得庆幸的是,该系统除了最后阶段外,还易于并行化。

 With thanks 至 Kyle Gesuelli 和 Ammon Brown 对于 proof 阅读, edits 和 suggestions. I 起源ally posted 上 的 框架 blog 在: //medium.com/frame-io-engineering/marketing-attribution-at-frame-io-8c2dbde14b37

避免使用顶级导入进行多次读取

最近我’一直在与需要导入大型JSON定义文件的各种应用程序一起使用,这些文件定义了复杂的应用程序设置。通常,代码库中的多个辅助模块都需要这些文件。所有软件工程原理都指向仅一次导入此类文件,而不管其使用了多少个辅助模块。

我的本能方法是在文件中读取一个主处理程序模块,然后将其内容作为类初始化参数传递:

主要_handler.py
蟒蛇
1
2
3
4
5
6
7
8
9
10
11
12
#main_handler.py
 
进口 json
 
模组1 进口 Class1
模组2 进口 Class2
 
打开(“ 设定.json”) f:
    设定 = json.加载(f)
 
在里面1 = Class1(设定=设定)
在里面2 = Class2(设定=设定)

问题是如果您有一个复杂的导入过程,并且要导入多个文件,它可能会开始看起来很凌乱。我最近发现,这种多重初始化参数方法不是’t实际上是必要的。

在Python中,您实际上可以在两个辅助模块(module1和module2)中导入相同的设置加载器模块,而python只会加载一次:

主要_handler.py
蟒蛇
1
2
3
4
5
6
7
#main_handler.py
 
模组1 进口 Class1
模组2 进口 Class2
 
在里面1 = Class1()
在里面2 = Class2()

模组1.py
蟒蛇
1
2
3
4
5
6
7
# 模组1.py
 
进口 设定_loader
 
Class1:
    定义 __在里面__():
        .设定 = 设定_loader.设定

模组2.py
1
2
3
4
5
6
7
# 模组2.py
 
进口 设定_loader
 
Class2:
    定义 __在里面__():
        .设定 = 设定_loader.设定

设定_loader.py
蟒蛇
1
2
3
4
5
6
7
#settings_loader.py
 
进口 json
 
打开(“ 设定.json”) f:
    打印 “正在加载设置文件!”
    设定 = json.加载(f)

现在,当我们在终端中对此进行测试时:

终端输出
贝壳
1
2
3
4
5
先生MAC:进口测试 脆弱的$
先生MAC:进口测试 脆弱的$
先生MAC:进口测试 脆弱的$ 蟒蛇 主要_handler.py
载入中 设定 文件!
先生MAC:进口测试 脆弱的$

尽管打电话 进口 设定_loader  两次,Python实际上只调用了一次。这是非常有用的,但是如果您实际上想两次导入文件,也可能引起头痛。如果是这样,那么我会将设置导入器包含在 __在里面__()  每个ClassX实例化两次。

在您的代码中模拟出API调用

使用任何积极开发的(python)编码项目,您都可以’re和您的团队每周将进行数百次相同的测试。如果有’向那里的任何第三方资源发出HTTP请求,这可能会导致问题。 API调用可能是一种支出,过多地刮擦同一源可能会导致IP黑名单,并且这些调用可能会减慢整个测试过程的速度,从而给代码部署过程增加了额外的负担。

为了解决这个问题,我们可以使用Python’的模拟库。模拟对于创建伪函数调用,伪类和其他可以返回伪值的伪对象非常有用。在大多数情况下,测试实际上是在测试应用程序如何解析数据,而不是第三方服务的可靠性。 API’的响应通常是相同的。模拟可以让您模拟API’响应并解析其数据,而不必每次都真正拨打电话。

It’设置起来非常棘手,所以我想我会写一个教程。情况设置有几个组成部分,但我’我会尽量解释一下。让’s说有一个提供一些有用的API响应的服务。那里’是一个由肯尼斯·雷茨(Kenneth Reitz)设置的网站HTTPBin,用于测试HTTP库,我们将在这里使用它。查看: //httpbin.org/ip。内容如下:

的JavaScript
1
2
3
{
  “起源”: “ 123.123.123.123”,
}

让’s说我们的程序想获取IP地址中的 起源 领域。对–一个毫无意义的程序,但这类似于您的许多情况’ll 恩counter.

这里’是一个完全过度设计的类,无法从此服务获取数据。在类中初始化时 __在里面__,它将创建一个指向HTTPBin的base_url变量。主要的处理程序功能是 得到_ip 功能,只是抓住了那个领域’的内容。首先拨打 api_call 使用 请求.get 获取该HTTP数据。

my_module.py
蟒蛇
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
要求 进口 得到
 
我的课:
    定义 __在里面__():
        .基础_url = "//httpbin.org/ip"
 
    定义 api_call():
        “”“进行API调用”“”
 
        结果 = 得到(.基础_url)
        如果 结果.:
            返回 结果.json()
 
        返回
 
    定义 得到_ip():
        “”“从API响应中获取语言”“”
 
        尝试:
            数据 = .api_call()
            返回 数据['起源']
         (TypeError, 键Error, IndexError):
            返回 “对{0}的HTTP请求失败”.格式(.基础_url)

要简单地运行此代码(在Python 贝壳中):

1
2
3
4
>>> 进口 my_module
>>> 测试 = my_module.我的课()
>>> 测试.得到_ip()
u'123.123.123.123'

如果我们要模拟出来怎么办 请求.get? 嘲笑模块文档尚不清楚如何在类中定位特定功能。事实证明,最简单的方法不是 魔术模拟 要么 返回_value 而是使用反直觉的命名“副作用”特征。这是测试模块的预模拟:

测试_my_module.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
进口 单元测试
 
my_module 进口 我的课
 
测试分类器(单元测试.测试用例):
    定义 设定():
        .ip_grabber = 我的课()
    
    定义 测试_ip_grabber():
        ip = .ip_grabber.得到_ip()
        .如sertIsInstance(ip, 基本串, “ 知识产权应该是字符串”)
        .断言等于(ip.计数('。'), 3, “ 知识产权应该有3个点”)
 
如果 __名称__ == '__主要__':
    单元测试.主要()

如您所见,这是一组标准测试,用于检查 ip_grabber 函数返回有效的IP地址。它运行如下:

1
2
3
4
5
6
脆弱的$ 蟒蛇 测试_my_module.py
.
-----------------------------------
1 测试 0.293s
 

但是,这里的问题在于,每次运行测试时,它将调用实际的API。为了阻止这个,让’集成了模拟模块:

蟒蛇
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
进口 单元测试
进口 嘲笑
 
my_module 进口 我的课
 
fake_get():
    定义 __在里面__(, 网址):
        . = 真正
    定义 json():
        返回 {'起源': '123'}
 
测试分类器(单元测试.测试用例):
    定义 设定():
        .ip_grabber = 我的课()
    
    @嘲笑.补丁('my_module.get', 副作用=fake_get)
    定义 测试_ip_grabber(, fake_get):
        
        ip = .ip_grabber.得到_ip()
        
        .如sertIsInstance(ip, 基本串, “ 知识产权应该是字符串”)
        .断言等于(ip.计数('。'), 3, “ 知识产权应该有3个点”)
 
如果 __名称__ == '__主要__':
    单元测试.主要()

这里 we’ve:

  1. 导入了模拟模块。注意:如果您收到有关“wraps” 在 的 “six” 模组 的n 它 是 almost certainly 因为 您 有 more than 上e 安装ation 的 六 要么 嘲笑 和 上e needs 至 是 deleted.
  2. 创建一个假函数 fake_get to 更换 请求.get 用。这实际上只是返回“123”现在,您可以在下面查看它如何使测试失败。
  3. 在test_ip_grabber函数周围添加了mock.patch包装器。这里非常重要的是指定函数名,因为它是在my_module中导入的,而不是在Python标准库中出现的;即我们正在做“my_module.get” rather than “requests.get”. 的 副作用 = 的n says 取代 那 与 什么ever 功能 we 想.
  4. 现在必须将副作用指定的伪造函数添加为该函数的参数。

运行此,我们得到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
脆弱的$ 蟒蛇 测试_my_module.py
F
======================================================================
失败: 测试_ip_grabber (__主要__.测试分类器)
-----------------------------------
追溯 (最近 呼叫 持续):
  文件 “ /Library/Python/2.7/site-packages/mock/mock.py”, 线 1305, 修补
    返回 功能(*args, **钥匙war)
  文件 “ 测试_my_module.py”, 线 19, 测试_ip_grabber
    .断言等于(ip.计数('。'), 3, “ 知识产权应该有3个点”)
断言错误: 知识产权 应该 3
 
-----------------------------------
1 测试 0.002s
 
失败 (失败=1)

嘲笑’s 副作用 已取代 请求.get -要通过此操作,只需更换  返回 {'起源': '123'} with 返回 {'起源': '123.123.123.123'}  and 跑 again:

1
2
3
4
5
6
脆弱的$ 蟒蛇 测试_my_module.py
.
-----------------------------------
1 测试 0.000s
 

测试通过和零HTTP流量! -

修复ifup / 如果up-eth中的Django / 流浪汉错误

我通常使用本地无业游民实例测试django项目。 流浪汉创建了一个运行django项目的虚拟机,该虚拟机可立即识别代码更改。但是,我最近正在运行测试,因此VM突然开始输出错误消息,如下所示。注意:我’已编辑这些终端输出的某些部分。

(滚动到这篇文章的底部以跳至解决方案)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(网络应用) [流浪汉@项目 流浪汉]$ ./管理.py 测试
追溯 (最近 呼叫 持续):
  文件 “ ./manage.py”, 线 8, <模组>
    执行_from_command_line(系统.精油)
  文件 “ /home/vagrant/venvs/webapp/lib/python2.7/site-packages/django/core/management/__init__.py”, 线 353, 执行_from_command_line
  文件 “ /home/vagrant/venvs/webapp/lib/python2.7/site-packages/django/core/management/__init__.py”, 线 345, 执行
  文件 “ /home/vagrant/venvs/webapp/lib/python2.7/site-packages/django/core/management/commands/test.py”, 线 30, 跑_from_argv
  文件 “ /home/vagrant/venvs/webapp/lib/python2.7/site-packages/django/core/management/base.py”, 线 348, 跑_from_argv
  文件 “ /home/vagrant/venvs/webapp/lib/python2.7/site-packages/django/core/management/commands/test.py”, 线 74, 执行
  文件 “ /home/vagrant/venvs/webapp/lib/python2.7/site-packages/raven/contrib/django/management/__init__.py”, 线 41, 新_execute
  文件 “ /home/vagrant/venvs/webapp/lib/python2.7/site-packages/django/core/management/base.py”, 线 413, 执行
  文件 “ /home/vagrant/venvs/webapp/lib/python2.7/site-packages/django/utils/translation/__init__.py”, 线 147, 启用
  文件 “ /home/vagrant/venvs/webapp/lib/python2.7/site-packages/django/utils/translation/trans_real.py”, 线 216, 启用
  文件 “ /home/vagrant/venvs/webapp/lib/python2.7/site-packages/django/utils/translation/trans_real.py”, 线 205, 翻译
  文件 “ /home/vagrant/venvs/webapp/lib/python2.7/site-packages/django/utils/translation/trans_real.py”, 线 118, __在里面__
IOError: 没有 翻译 档案 发现 对于 默认 语言 -我们.

没有翻译文件?一世’我从来没有听说过他们。认为这可能是一个随机错误,因此我尝试再次运行测试并得到:

1
2
(网络应用) [流浪汉@项目 流浪汉]$ ./管理.py 测试
-重击: ./管理.py: /我们r/箱子/环保: 口译员: 输入值/输出 错误

我尝试注销实例,但遇到I / O错误:

1
2
(网络应用) [流浪汉@项目 流浪汉]$ 登出
-重击: /首页/流浪汉/.重击_logout: 输入值/输出 错误

尝试再次ssh进入VM:

1
2
先生-个人电脑:项目 脆弱的$ 流浪汉 ssh
ssh_exchange_identification: 连接 关闭 通过 远程 主办

有时“关闭并重新打开”解决方案可以工作,所以让’s尝试流浪者重装:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
先生-个人电脑:项目 脆弱的$ 流浪汉 重装
==> 默认: 尝试中 优美 关掉 虚拟机...
    默认: 来宾 通讯 可以 已建立! 这个 通常 因为
    默认: SSH协议 跑步, 认证方式 信息 原为 变了,
    默认: 要么 一些 其他 联网 问题. 流浪汉 , 如果
    默认: .
==> 默认: 强迫 关掉 虚拟机...
==> 默认: 检查 如果 'bento / centos-7.1' 向上 日期...
==> 默认: 清算 任何 先前 转发 港口...
==> 默认: 固定 港口 碰撞 对于 22 => 2222. 现在 港口 2200.
==> 默认: 清算 任何 先前 网络 介面...
==> 默认: 准备中 网络 介面 基于 组态...
    默认: 适配器 1: t
    默认: 适配器 2: 仅主机
==> 默认: 转寄 港口...
    默认: 22 => 2200 (适配器 1)
==> 默认: 跑步 “预启动” 虚拟机 定制...
==> 默认: 正在启动 虚拟机...
==> 默认: 等候 对于 开机. 这个 可能 采取 a 几个 分钟...
    默认: SSH协议 地址: 127.0.0.1:2200
    默认: SSH协议 用户名: 流浪汉
    默认: SSH协议 认证 方法: 私人的
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 连接 超时. 重试...
^C==> 默认: 等候 对于 清理 之前 退出...
先生-个人电脑:项目 脆弱的$ 流浪汉 退出 清理 到期 外部 打断.

此轮超时错误。该错误似乎与身份验证有关,但它’并非全部。尽管未正确设置,但VM仍根据全局状态运行,这有点奇怪。

1
2
3
4
先生-个人电脑:项目 脆弱的$ 流浪汉 全球-状态
id       名称    提供者   州    目录                                                
--------------------------------------------
0e8faad  默认 虚拟盒子 跑步  /卷数/数据/用户数/脆弱的/文件资料//项目

我也跑了 名为VirtualBox的GUI 有时对于可视化笔记本电脑上的所有VM十分方便。检查那里,它似乎也存在–所以全局状态’t lying 至 我们. 让’s 尝试 停ing 它:

1
2
3
4
5
6
7
先生-个人电脑:项目 脆弱的$ 流浪汉
==> 默认: 尝试中 优美 关掉 虚拟机...
    默认: 来宾 通讯 可以 已建立! 这个 通常 因为
    默认: SSH协议 跑步, 认证方式 信息 原为 变了,
    默认: 要么 一些 其他 联网 问题. 流浪汉 , 如果
    默认: .
==> 默认: 强迫 关掉 虚拟机...

这次强制关闭。到目前为止,调试此错误是’不好完全奇怪,因为VM事先运行良好。在产生相同的超时后流浪汉:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
先生-个人电脑:项目 脆弱的$ 流浪汉 向上
带来 '默认' 向上 'virtualbox' 提供者...
==> 默认: 检查 如果 'bento / centos-7.1' 向上 日期...
==> 默认: 清算 任何 先前 转发 港口...
==> 默认: 固定 港口 碰撞 对于 22 => 2222. 现在 港口 2200.
==> 默认: 清算 任何 先前 网络 介面...
==> 默认: 准备中 网络 介面 基于 组态...
    默认: 适配器 1: t
    默认: 适配器 2: 仅主机
==> 默认: 转寄 港口...
    默认: 22 => 2200 (适配器 1)
==> 默认: 跑步 “预启动” 虚拟机 定制...
==> 默认: 正在启动 虚拟机...
==> 默认: 等候 对于 开机. 这个 可能 采取 a 几个 分钟...
    默认: SSH协议 地址: 127.0.0.1:2200
    默认: SSH协议 用户名: 流浪汉
    默认: SSH协议 认证 方法: 私人的
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 连接 超时. 重试...

让’尝试完全销毁无业游民的实例….

1
2
3
4
5
6
先生-个人电脑:项目 脆弱的$ 流浪汉 破坏
    默认: 当然 破坏 '默认' 虚拟机? [y/N] y
==> 默认: 强迫 关掉 虚拟机...
==> 默认: 毁灭 虚拟机 关联的 驱动器...
==> 默认: 跑步 清理 任务 对于 “可以” 供应者...
==> 默认: 跑步 清理 任务 对于 'hostsupdate' 供应者...

从头开始:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
先生-个人电脑:项目 脆弱的$ 流浪汉 向上
带来 '默认' 向上 'virtualbox' 提供者...
==> 默认: 输入 基础 'bento / centos-7.1'...
==> 默认: 匹配 苹果电脑 地址 对于 NAT 联网...
==> 默认: 检查 如果 'bento / centos-7.1' 向上 日期...
==> 默认: 设置 名称 虚拟机: 项目
==> 默认: 固定 港口 碰撞 对于 22 => 2222. 现在 港口 2200.
==> 默认: 清算 任何 先前 网络 介面...
==> 默认: 准备中 网络 介面 基于 组态...
    默认: 适配器 1: t
    默认: 适配器 2: 仅主机
==> 默认: 转寄 港口...
    默认: 22 => 2200 (适配器 1)
==> 默认: 跑步 “预启动” 虚拟机 定制...
==> 默认: 正在启动 虚拟机...
==> 默认: 等候 对于 开机. 这个 可能 采取 a 几个 分钟...
    默认: SSH协议 地址: 127.0.0.1:2200
    默认: SSH协议 用户名: 流浪汉
    默认: SSH协议 认证 方法: 私人的
    默认: 警告: 连接 超时. 重试...
    默认:
    默认: 流浪汉 不安全的 检测到. 流浪汉 自动地 更换
    默认: 这个 a 产生的 密钥对 对于 更好 安全.
    默认:
    默认: 插入 产生的 上市 来宾...
    默认: 拆下 不安全的 来宾 如果 's 当下...
    默认: 插入! 断开连接 重新连接 使用 SSH协议 ...
==> 默认: 开机 准备!
==> 默认: 检查 对于 来宾 加法 虚拟机...
==> 默认: 配置中 使能 网络 介面...
以下 SSH协议 命令 回应 a -出口 状态.
流浪汉 假设 这个 手段 命令 失败了!
 
<跨度 风格=“颜色:#ff0000;”>/箱子/如果up 恩p0s8
 
标准输出 命令:
 
错误    : [/等等/系统配置/网络-剧本/如果up-道德] 错误, 一些 其他 主办 已经 用途 地址 192.168.111.224.
 
 
斯特德 命令:
 
</跨度>

那’这是一个非常奇怪的错误。也许某些事情随机失败了?

1
2
3
4
先生-个人电脑:项目 脆弱的$ 流浪汉 向上
带来 '默认' 向上 'virtualbox' 提供者...
==> 默认: 检查 如果 'bento / centos-7.1' 向上 日期...
==> 默认: 虚拟盒子 虚拟机 已经 跑步.

显然,它仍然创建了VM。 SSH协议进入它可以做到这一点:

1
2
3
4
5
6
7
先生-个人电脑:项目 脆弱的$ 流浪汉 ssh
[流浪汉@本地主机 ~]$
[流浪汉@本地主机 ~]$ ls
[流浪汉@本地主机 ~]$
[流浪汉@本地主机 ~]$
[流浪汉@本地主机 ~]$ 登出
连接 127.0.0.1 关闭.

奇怪的是没有文件!还是有东西’t 启动 properly.

1
2
3
[流浪汉@本地主机 ~]$ 光盘 /
[流浪汉@本地主机 /]$ ls
箱子  开机  开发者  等等  首页  LIB  的lib64  媒体  nt  选择  处理  根  跑  箱子  srv  系统  tmp  我们r  变种

在 这个 point I 原为 得到ting a bit frustrated 和 started 至 Google 的 错误. 的 最 relevant blog post I 可以 找 原为 Mike Berggren’s solution 这里: http://mikeberggren.com/post/100289806126/if-up。他解决了这个问题并报告:“我会为您省去其余的细节,但足以说明这一点,我们最终绕过了该检查并从主机运行了相同的命令。它返回了另一个声称拥有所有权的MAC地址“。这是否意味着他从字面上注释掉了进行检查的代码行?他可能遇到了非常不同的问题,而我’我不是开发人员专家,但也许在那里’s a 更好 solution –也许那张支票是有原因的。

让’回顾一下前面提到的网络错误:

1
2
3
4
5
6
7
8
9
10
11
以下 SSH协议 命令 回应 a -出口 状态.
流浪汉 假设 这个 手段 命令 失败了!
 
/箱子/如果up 恩p0s8
 
标准输出 命令:
 
错误    : [/等等/系统配置/网络-剧本/如果up-道德] 错误, 一些 其他 主办 已经 用途 地址 192.168.111.224.
 
 
斯特德 命令:

删除流浪者文件,并显示相同的IP地址。这意味着该特定的无业游民总是被分配该IP地址。如果这是唯一的实例,那么该虚拟网络上的其他对象正在使用它吗?我的mac电脑内部存在某些问题。

1
2
先生-个人电脑:项目 脆弱的$ 流浪文件 | 格蕾p 111.224
  配置.虚拟机.网络 :私人的_network, ip: “ 192.168.111.224”

We can check 至 see 什么’s really 跑步 (aside 从 什么 全球-status 和 虚拟盒子 say) 通过 checking 跑步 处理es:

1
2
3
先生-个人电脑:项目 脆弱的$ ps 辅助 | 格蕾p -i vbox | 格蕾p 项目
脆弱的        67692   1.0  6.0  3077812 502624   ??  S    2016年3月22日  87:35.54 /应用领域/虚拟盒子.应用程式/内容/苹果系统/VBox无头 -评论 项目 -startvm (杂凑) -vrde 配置
脆弱的        21971   0.6  5.5  3023580 459532   ??  S     5:22PM   1:00.31 /应用领域/虚拟盒子.应用程式/内容/苹果系统/VBox无头 -评论 项目 -startvm (杂凑) -vrde 配置

Aha! 那里 are actually 2 的 的m. 让’销毁我们之前创建的无法运行的空白虚拟机,并查看是否有任何更改:

1
2
3
4
5
6
先生-个人电脑:项目 脆弱的$ 流浪汉 破坏
    默认: 当然 破坏 '默认' 虚拟机? [y/N] y
==> 默认: 强迫 关掉 虚拟机...
==> 默认: 毁灭 虚拟机 关联的 驱动器...
==> 默认: 跑步 清理 任务 对于 “可以” 供应者...
==> 默认: 跑步 清理 任务 对于 'hostsupdate' 供应者...

是的,它已经消失了:

1
2
先生-个人电脑:项目 脆弱的$ ps 辅助 | 格蕾p -i vbox
脆弱的        67692   1.3  6.0  3077812 502640   ??  R    2016年3月22日  87:35.98 /应用领域/虚拟盒子.应用程式/内容/苹果系统/VBox无头 -评论 项目 -startvm (杂凑) -vrde 配置

使用kill -9 [pid]删除它。

1
先生-个人电脑:项目 脆弱的$ -9 67692

现在让’尝试重新创建VM:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
先生-个人电脑:项目 脆弱的$ 流浪汉 向上
带来 '默认' 向上 'virtualbox' 提供者...
==> 默认: 输入 基础 'bento / centos-7.1'...
==> 默认: 匹配 苹果电脑 地址 对于 NAT 联网...
==> 默认: 检查 如果 'bento / centos-7.1' 向上 日期...
==> 默认: 设置 名称 虚拟机: 项目
==> 默认: 清算 任何 先前 网络 介面...
==> 默认: 准备中 网络 介面 基于 组态...
    默认: 适配器 1: t
    默认: 适配器 2: 仅主机
==> 默认: 转寄 港口...
    默认: 22 => 2222 (适配器 1)
==> 默认: 跑步 “预启动” 虚拟机 定制...
==> 默认: 正在启动 虚拟机...
==> 默认: 等候 对于 开机. 这个 可能 采取 a 几个 分钟...
    默认: SSH协议 地址: 127.0.0.1:2222
    默认: SSH协议 用户名: 流浪汉
    默认: SSH协议 认证 方法: 私人的
    默认: 警告: 连接 超时. 重试...
    默认: 警告: 远程 连接 断开. 重试...
    默认:
    默认: 流浪汉 不安全的 检测到. 流浪汉 自动地 更换
    默认: 这个 a 产生的 密钥对 对于 更好 安全.
    默认:
    默认: 插入 产生的 上市 来宾...
    默认: 拆下 不安全的 来宾 如果 's 当下...
    默认: 插入! 断开连接 重新连接 使用 SSH协议 ...
==> 默认: 开机 准备!
==> 默认: 检查 对于 来宾 加法 虚拟机...
==> 默认: 配置中 使能 网络 介面...
==> 默认: 安装 共享 资料夹...
    默认: /流浪汉 => /卷数/数据/用户数/脆弱的/文件资料//项目
==> 默认: 跑步 供应者: Ansible...

有用!

结论:

  • I’我仍然不确定为什么会首先发生这种情况。一开始的错误完全是突然的– I’d已在该虚拟机上运行了几周而没有任何问题。也许事实是我’d已经运行了这么长时间?
  • 流浪汉的全局状态和VirtualBox似乎不能完全准确地报告正在运行的虚拟机,因此绝对可以使用ps检查所有正在运行的vbox进程,并删除没有’t正确关闭。这让我想起了–全局状态下的修剪选项(//www.vagrantup.com/docs/cli/global-status.html),它可以修复持久性旧条目。

非常感谢Tony(http://blog.tonns.org/)以帮助解决此问题!

Extending MongoDB 找One() 功能ality 至 找Another()

给定一个可以使用的新MongoDB实例,通常很难理解其结构,因为与SQL不同,该数据库本质上没有架构。流行的初始工具是 Variety.js, which 找s all possible 领域 和 tells 您 的 types, occurrences 和 percentages 的 的m 在 的 D b.

但是,通常也可以查看字段的内容。为此,您可以使用 找One(), which grabs 什么 seems 至 是 的 持续 插入 record 来自 采集 和 pretty-prints 它 至 的 terminal. 这个 是 格蕾at, but 一些times 您 想 至 see more than 上e record 至 得到 a 更好 feel 对于 field contents. In 这个 post I’将向您展示我如何扩展Mongo来做到这一点。

(假设你’ve已经安装了mongo和git– I 采用  酿造 安装 蒙哥 from 的 自制程序包管理器 和git随附Mac上的XCode)

首先,让’s获得mongo的副本’s 码:

贝壳
1
2
脆弱的$ 光盘 ~/文件资料
脆弱的$ 吉特 克隆 https://的github.com/蒙哥db/蒙哥.git

这将在您的文档中创建一个文件夹,所以让’s 在spect 它:

贝壳
1
2
3
4
脆弱的$ 光盘 蒙哥
脆弱的$ ls
亚太地区-2.0.txt   GNU-股份公司-3.0.txt 构造       建筑脚本     distsrc          等等              转数              src
贡献.rst 自述文件           建立            Debian           docs             jstests          site_scons

那里’s quite a lot 的 档案 的re, 它 将 采取 a while 至 找 where 的 找One() 功能 是 located. Github’的存储库搜索返回太多结果,因此让’而是使用unix文件搜索。 MongoDB用JavaScript编写(并已编译),因此我们需要查找类似 找One = 功能( or 功能 找One( . Try 这个 search:

1
2
3
4
5
脆弱的$ 格蕾p -R "找One = 功能(" .
./建立/选择/蒙哥/蒙哥
./建立/选择/蒙哥/贝壳/蒙哥.cpp
./建立/选择/蒙哥/贝壳/蒙哥.o
./src/蒙哥/贝壳/采集.js

这两个标志是 -l  (小写的L)显示文件名,以及 R  搜索所有子目录。最后的句号表示搜索当前目录。您可以看到它在其中找到了一个javascript文件,“collection.js”. If 您 打开 它 向上 在 a text editor, 的 找One() 功能 是 listed:

的JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
数据库集合.原型.找One = 功能( 询问 , 领域, 选项, readConcern ){
    变种 光标 = 这个.(询问, 领域, -1 / *限制* /, 0 / *跳过* /,
        0 / * batchSize * /, 选项);
 
    如果 ( readConcern ) {
        光标 = 光标.readConcern(readConcern);
    }
 
    如果 ( ! 光标.hasNext() )
        返回 空值;
    变种 退回 = 光标.下一页();
    如果 ( 光标.hasNext() ) 错误( "找One has more than 1 结果!" );
    如果 ( 退回.$ )
         _getErrorWithCode(退回, “错误” + 至json(退回));
    返回 退回;
};

此代码也可以在mongodb 的github页面上找到: //github.com/mongodb/mongo/blob/master/src/mongo/shell/collection.js#L207

我们的功能将扩展findOne而不是查找另一条记录。这可以通过执行“find”使用完全相同的代码,但随后跳过随机的记录数。跳过量必须小于列出的记录数,不幸的是,这意味着我们必须运行两次查询。首先计算结果的数量,其次实际跳过一些数量。

复制 的 找One 功能 和 rename 它 至 找Another, 与 的se 线s 在 的 至p 在stead:

的JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
数据库集合.原型.找Another = 功能( 询问 , 领域, 选项, readConcern ){
    // Similar 至 找One but 返回s a different record 每 time
 
    //必须先进行两次查询,因为我们需要先知道计数,然后才能
    //随机跳过
    变种 总_records = 这个.(询问, 领域, -1, 0, 0, 选项).计数();
 
    // 随机 number generation 从: http://stackoverflow.com/a/7228322
    变种 随机Number = 数学.地板(数学.随机()*(总_records+1)+1);
    变种 光标 = 这个.(询问, 领域, -1, 随机Number, 0, 选项);
 
    如果 ( readConcern ) {
        光标 = 光标.readConcern(readConcern);
    }
 
    如果 ( ! 光标.hasNext() )
        返回 空值;
    变种 退回 = 光标.下一页();
    如果 ( 光标.hasNext() ) 错误( "找Another has more than 1 结果!" );
    如果 ( 退回.$ )
         _getErrorWithCode(退回, “错误” + 至json(退回));
    返回 退回;
};

  1. 获取查询返回的记录数(存储在total_records中)
  2. 生成一个介于1到计数之间的随机数(存储在randomNumber中)
  3. 再次使用该数字作为跳过查询(存储在光标中)

在JavaScript中生成范围内的随机数有点晦涩难懂,但我在StackOverflow上找到了一个有用的技巧来做到这一点: http://stackoverflow.com/a/7228322 in 上e 线. I’m 采用d 至 蟒蛇’s ultra simple 随机.randrange().

让’首先测试一下。您’我会注意到所有代码都可以在mongo中返回’s javascript 贝壳:

的JavaScript
1
2
3
4
5
6
7
8
9
10
11
脆弱的$ 蒙哥 127.0.0.1
MongoDB 贝壳 : 3.3.1-217-gdfaa843
连接中 : 本地主机
>
> 采用 my_db
切换的 D b my_db
> D b.柯尔.找One
功能 ( 询问 , 领域, 选项, readConcern ){
    变种 光标 = 这个.(询问, 领域, -1 / *限制* /, 0 / *跳过* /,
        0 / * batchSize * /, 选项);
...等等

您实际上可以在终端中实时替换此代码,尽管它赢得了’t 是 saved 上ce 您 close 它. Try first replacing 找One 与 a 你好 世界:

的JavaScript
1
2
3
4
> D b.柯尔.找One = 功能(){返回 '你好,世界'}
功能 (){返回 '你好,世界'}
> D b.柯尔.找One()
你好 世界

您可以先在终端中通过复制第一个等号之后的所有内容来测试我们的新功能。打开mongoDB 贝壳到您喜欢的数据库并输入 D b.我的收藏.找One =  然后粘贴功能。尝试调用它,它每次应返回不同的结果。

让’的补丁mongodb现在具有我们的功能。我们必须从刚刚下载的源代码编译mongo。

  1. Save 的 采集.js 文件 您 just edited 与 的 新 找Another() 功能
  2. 确保已安装C ++编译器。一世’m使用gcc(已使用安装)  酿造 安装 海湾合作委员会
  3. 检查您的处理器有多少个内核。根据Google的说法,我的2.7 GHz Intel i5有4个内核。
  4. 在同一终端窗口中(仍在mongo文件夹中),键入: 坏话 -j4 蒙哥  and press 恩ter. 的 4  这是我拥有的核心数量,并会认真加快速度。 坏话  是一个处理编译, 蒙哥  最后,这表明我们只想修补mongo’s 客户.

您 ’当scons检查所有内容时,会看到大量绿色文本,然后:

贝壳
1
2
3
4
5
6
7
8
9
10
脆弱的$ 坏话 -j4 蒙哥
坏话: 阅读 脚本 档案 ...
坏话 : 2.4.1
(等等 等等...)
检查 对于 C 标头 文件 x86intrin。H... (已缓存)
坏话: 完成 阅读 脚本 档案.
坏话: 建造 目标 ...
安装 文件: “构建/选择/蒙哥/蒙哥” “蒙哥”
坏话: 完成 建造 目标.
脆弱的$

它编译了!现在,我们必须用修改后的版本替换现有的mongo应用程序。让’s do a unix 找:

贝壳
1
2
3
4
5
6
7
8
9
10
11
12
脆弱的$ 须藤 / -名称 “蒙哥”
密码:
: /开发者/fd/3: a 目录
: /开发者/fd/4: a 目录
/我们r/本地/箱子/蒙哥
/我们r/本地/地窖/蒙哥db/3.2.0/箱子/蒙哥
/我们r/本地/图书馆/别名/蒙哥
/卷数/数据/用户数/脆弱的/文件资料//蒙哥
/卷数/数据/用户数/脆弱的/文件资料//蒙哥/建立/选择/蒙哥
/卷数/数据/用户数/脆弱的/文件资料//蒙哥/建立/选择/蒙哥/蒙哥
/卷数/数据/用户数/脆弱的/文件资料//蒙哥/蒙哥
/卷数/数据/用户数/脆弱的/文件资料//蒙哥/src/蒙哥

我们要替换/ 我们r / 本地 / 地窖 /中的mongo应用程序(brew安装到的位置)。让’将其备份,然后复制:

贝壳
1
2
脆弱的$ cp /我们r/本地/地窖/蒙哥db/3.2.0/箱子/蒙哥 /我们r/本地/地窖/蒙哥db/3.2.0/箱子/蒙哥_backup
脆弱的$ cp 蒙哥 /我们r/本地/地窖/蒙哥db/3.2.0/箱子/

现在,打开一个MongoDB 贝壳到您喜欢的数据库:

贝壳
1
2
3
4
5
6
7
8
脆弱的$ 蒙哥 127.0.0.1
MongoDB 贝壳 : 3.3.1-217-gdfaa843
连接中 : 本地主机
> 采用 my_db
> my_db.coll。找另外一个()
{
“_ID” : 对象编号("...
等等...

 Caveats:

  • 这可能真的很慢,因为它必须运行两次查询。但是,通常我不’t 加 super taxing queries 至 找One().
  • 如果使用brew重新安装/升级mongo,则可能会替换此功能–他们相当频繁地发布新版本。

改进措施

  • 该函数的作用类似于python生成器,保持状态并向前循环直到到达记录集的末尾。这将解决上面的任何缓慢问题,但随机性会降低。

将HTML表转换为Excel下载HTTP响应:慢速OLAP DB连接的黑客

总览

善科 (“Good fox”日本)是一个报告系统(在这里查看Github上的代码) 一世’是在过去两周内在Mozilla创建的。基本上,我的非技术同事对Tableau感到非常沮丧(“INNER JOIN和OUTER JOIN有什么区别?”),我决定为他们创建一个简单的仪表板界面。

它是一个简单的引导程序前端,它包含数据库的活动统计信息 赞助瓷砖. 您 can drill down 至 每 tile or 客户/partner 和 pivot 通过 things like 本地e, 国家 和 日期.

善科 ’s堆栈(从高到低)

一项新功能

加载分析页面之一时,将显示一个表格。我的同事希望能够将数据下载到Excel。我想出了4种可能的方法来实现此目的:

  1. 只需重新运行查询,在后端将结果格式设置为csv,然后将其保存并在window.open()文件位置即可。
  2. 自动保存每个分析请求服务器请求中的数据,并定期清除旧文件。
  3. 使用像 ExcelBuilder
  4. Send 的 数据 back 至 的 server, 格式 它, 和 的n back 至 的 客户 via an 如果rame

哪个是最佳解决方案?

  1. 这是有问题的,因为我们的重点是查询速度。 redshift数据库是一个 OLAP面向列的数据库和仅追加。这意味着添加数据的速度非常快,但是查询速度却很慢(通常超过6秒)。是的,它正在处理数十亿行这样令人难解的行,但是就等待这么长时间的用户体验而言并不是那么好。 ’如果他们已经有数据,则要再等待6秒钟重新运行分析。
  2. 听起来这可能最终会在客户端上存储大量数据,但是效果很好。在安全性方面,我’我不确定数据应该留在用户身上’不需要PC。
  3. 这没有’t work out so well –在Firefox中,文件命名错误。将来,我’d根据分析参数命名文件,例如<client>-<date>-<country>.xls
  4. 这个 是 的 weirdest solution, but 它 works! 烧瓶 是 跑步 本地ly so 它 是 actually very fast. 那里 are no huge JQuery/JavaScript complications 与 文件 permissions 和 的 fact 那 您 can manipulate 的 数据 easily 上 的 server 是 nice 至o.

解决方案4

该过程如下“Download 对于 Excel” button 是 clicked:

  1. 使用JavaScript引用HTML表并将其转换为数组数组
  2. 将iframe附加到DOM
  3. 将带有POST操作和隐藏字段的表单附加到iframe
  4. 将表内容插入隐藏字段’s value
  5. 提交表格
  6. 让 烧瓶 receive 的 POST 请求 和 格式 的 信息 如 a CSV
  7. 返回带有包含CSV的文件附件的HTTP响应

让’s implement 它

添加此功能以获取表内容并将其放入数组中
的JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
功能 convert_table_to_array() {
//将当前表转换为列表列表
可耐 = 文件.得到ElementById(“ impressions_table”) //该表在zenko中将始终称为this
//将表格转换为列表列表(即数组数组)
变种 数据 = [];
//元数据
col_count = 可耐.孩子们[0].孩子们[0].孩子们.长度 //列数
行_count = 可耐.孩子们[1].孩子们.长度 //行数
//获取标题(即包含列标题的第一行)
标头_cells = 可耐.孩子们[0].孩子们[0].孩子们
标头 = []
对于 (i=0;i<标头_cells.长度;i++) {
标头.(标头_cells[i].textContent)
}
数据.(标头)
//遍历每一行
行_cells = 可耐.孩子们[1].孩子们
对于 (i=0;i<行_cells.长度;i++) {
= 可耐.孩子们[1].孩子们[i].孩子们
//获取行中的每个单元格
行_content = []
对于 (j=0;j<.长度;j++) {
cell_content = [j].textContent.更换(“,”, ) //一些文字输入已经包含一个逗号,使事情变得混乱
行_content.(cell_content)
}
数据.(行_content)
}
返回 数据
}

那里 were 变种ious ways 至 do 这个 在 JQuery 与 可重复的.()  但我遇到了麻烦,仅使用.children引用细胞就容易得多。

这个 是 什么 是 呼叫ed 通过 的 button click event
的JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
功能 download_xls() {
//将当前表下载为excel文件
 
//1. Create an 如果rame
如果rame = 文件.createElement(“ 如果rame”)
如果rame.组Attribute(“宽度”, 1)
如果rame.组Attribute(“高度”, 1)
如果rame.组Attribute(“框架边框”, 0)
如果rame.组Attribute(“ src”, “关于:空白”)
 
//2. Create a 形成 那 can send 数据 至 烧瓶
形成 = 文件.createElement(“形成”)
形成.组Attribute(“方法”, “ POST”)
形成.组Attribute(“行动”, “ / download_excel”)
 
//3. Put 的 table 数据 在to a hidden field 在 那 形成
数据 = 文件.createElement(“输入”)
数据.组Attribute(“类型”, “隐”)
数据.组Attribute(“值”, convert_table_to_array())
数据.组Attribute(“名称”, “数据”)
//4. Append 的se 新 elements 至 的 DOM
形成.应用程式endChild(数据)
如果rame.应用程式endChild(形成)
文件.身体.应用程式endChild(如果rame)
//5. Send 的f 的 数据
形成.提交()
}

然后,(本地运行中的)Flask将在以下位置接收POST请求: /download_excel . 让’s 组 向上 的 路线:

烧瓶路线
蟒蛇
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#接受POST数据(大于GET数据)
@应用程式.路线('/ download_excel', 方法=['得到', 'POST'])
定义 download_excel():
“”“根据收到的帖子信息创建文件下载”“”
#POST数据可通过request.form上的字典进行访问
数据 = 请求.形成[“数据”]
数据 = 数据.分裂(“,”) #以逗号分隔
#数据是列表的列表,例如[[1,2],[3,4]],但不幸的是发送了
#如  [1,2,3,4]。但是,我们知道有6列,因此我们可以将其拆分
#up 在to 六es 与 a list comprehension
数据 = [数据[x:x+6] 对于 x Xrange(0, (数据), 6)]
#N现在每个人都用逗号重新加入,所以它很csv-ish
数据 = “ \ n”.加入([','.加入(x) 对于 x 数据])
响应 = make_response(数据)
#返回带有附件的HTTP响应
响应.标头[“内容处置”] = “附件;文件名= 数据.csv”
返回 响应

现在,当用户单击按钮时:

下载Excel链接

他们立即得到:

下载弹出窗口

对不起,我可以’t show 什么 它 looks like 在 Excel 因为 的 数据 是n’目前还没有公开。所有代码均可用 在github上!

然而,一件奇怪的事情是表格没有’t出现在检查器中(在Chrome或Firefox中):

在检查器中不可见

不过,您可以使用一些相当长的吸气剂来访问它:

why.jpg

未来功能 

  • 这些文件的名称可能比data.csv更直观–可能是网址中出现的各种情况的组合’s 询问 string
  • 可容纳超过6行的表格。使用不同的定界符(例如,“###”.
  • 如果有好处,请创建一个.xls文件而不是CSV文件

在Firefox扩展中使用Web 工人

Web 工人允许您在诸如Firefox之类的浏览器中在后台运行代码。这是将其构建到Firefox扩展中的方法,这与在页面上正常创建一个扩展略有不同。这样做的文档基本上不存在,所以希望您’ll 找 这个 采用ful.

请确保您具有与开发环境相似的开发环境 在我以前的帖子中描述过。

工人如何工作?

  • / 数据 /中的工作程序未直接连接到/ LIB /中的脚本
  • 但是,他们可以通过相互发送消息进行通信
  • 这些消息仅是文本,因此可以包含序列化的JSON,但仅此而已
  • 您 ’下面会注意到,我们基本上只是在两个脚本之间添加消息

工人的代码

导航到/ 数据 /目录并创建一个名为hello_world.js的文件

贝壳
1
2
3
4
5
6
> 密码
/用户数/脆弱的/文件资料/测试
> ls
数据 LIB .json 测试
> 光盘 数据/
> vim 你好,世界.js

现在在其中粘贴以下内容(vim的新用户,请按 i  to start typing 和 退出  followed 通过 :q  to save):

的JavaScript
1
2
3
4
5
//工人的代码
 
.消息 = 功能(信息FromClient) {
    .postMessage("你好 " + 信息FromClient.数据);
};

这个 says 那 whenever 的 工人 receives a 信息 来自 客户, 的n send a 信息 back 与 的 word “Hello” prepended.

这里的一个注意事项:在工人中, ’使用有用的功能  安慰.日志(“信息”) , 在stead 采用  倾倒(“信息”)

让’从主代码中调用工人

让’导航回到 /LIB/  folder 和 edit 的 主要.js  文件,这是在扩展程序中运行的第一件事。

贝壳
1
2
> 光盘 ../LIB/
> vim 主要.js

粘贴以下代码:

的JavaScript
1
2
3
4
5
6
7
变种 工人 = 工人(“ 你好,世界.js”);
 
工人.消息 = 功能(e) {
    安慰.日志(e.数据);
};
 
工人.postMessage(“马修”);

然后跑  cfx  . 您 ’会发现一个混乱的错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
> cfx
使用 二元 '/Applications/Firefox.app/Contents/MacOS/firefox-bin'.
使用 个人资料 '/var/folders/p1/zzdzcrrx6pq96hgsmy5xjqmh0000gp/T/tmpgFixDP.mozrunner'.
安慰.错误: 测试:
  信息: ReferenceError: 工人 定义的
  叠放:
    @资源://jid1-zmowxggdley0aa-at-jetpack/test/lib/main.js:1:9
CuddlefishLoader/选项<.加载@资源://gre/modules/commonjs/sdk/loader/cuddlefish.js:129:18
@资源://gre/modules/commonjs/sdk/addon/runner.js:138:19
启动/</<@资源://gre/modules/commonjs/sdk/addon/runner.js:81:7
处理程序.原型.处理@资源://gre/modules/Promise-backend.js:865:23
这个.无极行者.沃克环@资源://gre/modules/Promise-backend.js:744:7
 
*************************
A 编码 例外 原为 抛出 a 诺言 解析度 打回来.
看到 https://developer.mozilla.org/Mozilla/JavaScript_code_modules/Promise.jsm/Promise
 
充分 信息: ReferenceError: 工人 定义的
充分 : @资源://jid1-zmowxggdley0aa-at-jetpack/test/lib/main.js:1:9
CuddlefishLoader/选项<.加载@资源://gre/modules/commonjs/sdk/loader/cuddlefish.js:129:18
@资源://gre/modules/commonjs/sdk/addon/runner.js:138:19
启动/</<@资源://gre/modules/commonjs/sdk/addon/runner.js:81:7
处理程序.原型.处理@资源://gre/modules/Promise-backend.js:865:23
这个.无极行者.沃克环@资源://gre/modules/Promise-backend.js:744:7
 
*************************
安慰.错误: 测试:
  信息: ReferenceError: 工人 定义的
  叠放:
    @资源://jid1-zmowxggdley0aa-at-jetpack/test/lib/main.js:1:9
CuddlefishLoader/选项<.加载@资源://gre/modules/commonjs/sdk/loader/cuddlefish.js:129:18
@资源://gre/modules/commonjs/sdk/addon/runner.js:138:19
启动/</<@资源://gre/modules/commonjs/sdk/addon/runner.js:81:7
处理程序.原型.处理@资源://gre/modules/Promise-backend.js:865:23
这个.无极行者.沃克环@资源://gre/modules/Promise-backend.js:744:7

啊哈!这里的关键是:  ReferenceError: 工人 定义的 。这是因为Firefox扩展程序改用了ChromeWorker。我们需要将其粘贴在main.js中,方法是将其粘贴在顶部:

的JavaScript
1
变种 {ChromeWorker} = 要求(“铬”)

并将引用hello_world.js文件的行更改为调用ChromeWorker:

的JavaScript
1
2
// 变种 工人 = 新 工人(“ 你好,世界.js”); //删除此
变种 工人 = ChromeWorker(“ 你好,世界.js”); //添加它

好吧让’尝试再次运行它!尝试  cfx  。 WTF另一个错误?

贝壳
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
> cfx
使用 二元 '/Applications/Firefox.app/Contents/MacOS/firefox-bin'.
使用 个人资料 '/var/folders/p1/zzdzcrrx6pq96hgsmy5xjqmh0000gp/T/tmpJJXeC4.mozrunner'.
安慰。错误: 测试:
  信息: 错误: 格式错误 脚本 URI: 你好,世界.js
  叠放:
    @资源://jid1-zmowxggdley0aa--喷气背包/测试/LIB/主要.js:3:14
CuddlefishLoader/选项<。加载@资源://格蕾/模组s/普通js/sdk/装载机/ud鱼.js:129:18
@资源://格蕾/模组s/普通js/sdk/添加在/跑步者.js:138:19
启动/</<@资源://格蕾/模组s/普通js/sdk/添加在/跑步者.js:81:7
处理程序。原型。处理@资源://格蕾/模组s/诺言-后端.js:865:23
这个.PromiseWalker.walkerLoop@资源://格蕾/模组s/诺言-后端.js:744:7
 
安慰。错误: 测试:
  信息: 错误: 格式错误 脚本 URI: 你好,世界.js
  叠放:
    @资源://jid1-zmowxggdley0aa--喷气背包/测试/LIB/主要.js:3:14
CuddlefishLoader/选项<。加载@资源://格蕾/模组s/普通js/sdk/装载机/ud鱼.js:129:18
@资源://格蕾/模组s/普通js/sdk/添加在/跑步者.js:138:19
启动/</<@资源://格蕾/模组s/普通js/sdk/添加在/跑步者.js:81:7
处理程序。原型。处理@资源://格蕾/模组s/诺言-后端.js:865:23
这个.PromiseWalker.walkerLoop@资源://格蕾/模组s/诺言-后端.js:744:7

这里的关键是:  格式错误 脚本 URI: 你好,世界.js 。此隐秘错误是因为Firefox可以’尚未访问 /数据/  夹。我们必须使用SDK的另一部分来启用对其的访问。

打开 主要.js  并将其放在顶部:

的JavaScript
1
变种 = 要求(“ sdk /自我”);

现在我们可以使用该功能 .数据.网址() 。当您将文件名作为第一个参数时,它将返回一个字符串,例如  资源://jid1-zmowxggdley0aa-at-jetpack/test/data/whatever_file.js 在扩展名的情况下正确地引用它。修改工作程序导入行,如下所示:

的JavaScript
1
2
//让worker = 新 工人(“ 你好,世界.js”); //删除此
工人 = ChromeWorker(.数据.网址(“ 你好,世界.js”)); //添加这个

现在让’使用以下命令再次运行扩展程序 cfx  :

1
2
3
4
> cfx
使用 二元 '/Applications/Firefox.app/Contents/MacOS/firefox-bin'.
使用 个人资料 '/var/folders/p1/zzdzcrrx6pq96hgsmy5xjqmh0000gp/T/tmppvMjZp.mozrunner'.
安慰.日志: 测试: 你好 马修

是的,它有效!工人退回了消息“你好 马修“.

常问问题

  • 这是什么 {符号}  mean?

它的简写为:

1
2
变种 = 要求(“铬”)
变种 工人 = [“ ChromeWorker”]

基本上这意味着  要求(“铬”) 返回一个Object,我们只需要键引用的值“ChromeWorker”。这是从JavaScript对象提取内容的非常简洁的方式,将来会派上用场。

  • 为什么现在将Worker称为ChromeWorker?我们在用Google Chrome做些什么吗?

这是一个命名巧合,与浏览器中的Chrome无关。在这种情况下,Chrome指的是Firefox插件内部。

设置Firefox扩展的开发环境。

这是我用来创建简单的Firefox扩展的方法。本教程是t的前身他的下一篇关于使用Web 工作人员 (即允许代码在后台线程上运行)。

搭建环境

We’将需要Firefox插件SDK。这是python文件的集合,可让您运行测试版(可选为空白)的Firefox。要下载它:

贝壳
1
脆弱的13338:添加在 脆弱的$ 得到 https://ftp.mozilla.org/酒馆/Mozilla.org/实验室/喷气背包/喷气背包-sdk-最新。柏油.gz

现在解压缩并删除压缩包:

1
2
脆弱的13338:添加在 脆弱的$ 柏油 -zxvf 喷气背包-sdk-最新.柏油.z
脆弱的13338:添加在 脆弱的$ R M -f 喷气背包-sdk-最新.柏油.z

转到目录并启动特殊的shell:

1
2
3
4
脆弱的13338:添加在 脆弱的$ 光盘 添加在-sdk-1.17/
脆弱的13338:添加在-sdk-1.17 脆弱的$ 资源 箱子/启用
欢迎 -开发包. 对于 docs, 访问 https://addons.mozilla.org/en-US/developers/docs/sdk/latest/
(添加在-sdk-1.17)脆弱的13338:添加在-sdk-1.17 脆弱的$

现在您可以看到shell已经在提示的括号中添加了(addon-sdk-1.17)。这意味着该窗口可能是文本的一半,因此我们可以使用以下命令来减少该文本:

1
2
(添加在-sdk-1.17)脆弱的13338:添加在-sdk-1.17 脆弱的$ PS1="> "
>

干净得多! -

设置扩展模板

现在我们有了这个特殊的addon-sdk 贝壳,导航回到您的文档并为我们的扩展程序创建一个新文件夹。

1
2
3
> 光盘 ~/文件资料/
> 麦克迪尔 教程
> 光盘 教程

这个特殊的shell包含各种有用的命令,它们看起来都像  cfx y 。有关他们的更多信息,请参见 这里。在这种情况下,我们使用  cfx 在里面

1
2
3
4
5
6
7
8
9
10
11
12
> cfx 在里面
* LIB 目录 被创造
* 数据 目录 被创造
* 测试 目录 被创造
* 产生的 标识 自动地: jid1-FYWu7Ld5UwDbRw
* .json 书面
* 测试/测试-主要.js 书面
* LIB/主要.js 书面
 
您 r 样品 - 现在 准备.
“ cfx测试” 测试 “ cfx运行” 尝试 .  好玩!
>

让’s 在spect 什么 原为 被创造:

贝壳
1
2
3
4
5
6
7
8
> ls -h
8
w-r-x   6 脆弱的  员工   204B 20 十一月 16:47 .
w---+ 29 脆弱的  员工   986B 20 十一月 16:45 ..
w-r-x   2 脆弱的  员工    68B 20 十一月 16:47 数据
w-r-x   3 脆弱的  员工   102B 20 十一月 16:47 LIB
-w-r-r-   1 脆弱的  员工   174B 20 十一月 16:47 .json
w-r-x   3 脆弱的  员工   102B 20 十一月 16:47 测试

  •  LIB  包含一个名为 主要.js  这是所有扩展代码的主要处理程序文件
  • 数据  为空,但可用于存储工作程序(我们将在后面介绍)或大数据文件等内容
  • 测试  可以包含单元测试(很难设置,但对以后的测试驱动开发很有用)
  • .json  包含有关扩展的元数据–版本号,创建者名称,描述,许可等

您可以开始在main.js中编写代码,它将在浏览器中运行。完成后,使用  cfx  to 测试 它!

请参阅下一个教程,了解如何使用网络工作者编写firefox扩展!