4

我的服务器上有一堆单词表,我一直在计划制作一个简单的开源 JSON API,如果密码在列表1上,它会返回,作为一种验证方法。我正在使用 Flask 在 Python 中执行此操作,如果输入存在,则实际上只是返回。

一个小问题:词表总计约 1.5 亿个条目,以及 1.1GB 的文本。

我的 API(最小)如下。将每一行存储在 MongoDB 中并重复查找是否更有效,或者使用单例将整个内容存储在内存中,并在我调用时在启动时填充它app.run?还是这些差异是主观的?
此外,做后者甚至是一种好习惯吗?我认为如果我向公众开放,查找可能会开始变得繁重。我也有人建议使用Trie进行有效搜索。

更新:我做了一些测试,文档搜索速度非常慢,记录数量如此之多。对需要有效搜索的单列数据使用具有适当索引的数据库是否合理?

from flask import Flask
from flask.views import MethodView
from flask.ext.pymongo import PyMongo
import json

app = Flask(__name__)
mongo = PyMongo(app)

class HashCheck(MethodView):

  def post(self):
    return json.dumps({'result' : 
      not mongo.db.passwords.find({'pass' : request.form["password"])})
    # Error-handling + test cases to come. Negate is for bool.

  def get(self):
    return redirect('/')

if __name__ == "__main__":
  app.add_url_rule('/api/', view_func=HashCheck.as_view('api'))
  app.run(host="0.0.0.0", debug=True)

1:我是个安全狂。我在我的登录表单中使用它并拒绝常见的输入。其中一个词表是UNIQPASS。

4

4 回答 4

4

鉴于您的列表完全是静态的并且适合内存,我看不出使用数据库的令人信服的理由。

我同意 Trie 对你的目标是有效的。哈希表也可以。

PS:Python 的 Global Interpreter Lock 太糟糕了。如果您使用具有真正多线程的语言,则可以利用不变的数据结构并在具有共享内存的多个内核上运行服务器。

于 2013-05-05T01:08:16.347 回答
4

我建议的是一种混合方法。在提出请求时进行两次检查。第一个在本地缓存中,第二个在 MongoDB 存储中。如果第一个失败但第二个成功,则将其添加到内存缓存中。随着时间的推移,应用程序将在最常见的“错误密码”/记录中“出错”。

这有两个优点:
1) 常用词从内存中被快速拒绝。
2)启动成本接近于零,并在许多查询中摊销。

在 MongoDB 中存储单词列表时,我会让 _id 字段保存每个单词。默认情况下,您将获得一个 ObjectId,在这种情况下这完全是浪费。然后,我们还可以利用 _id 上的自动索引。我怀疑您看到的性能不佳是由于“通过”字段上没有索引。您也可以尝试在“通过”字段中添加一个:

mongo.db.passwords.create_index("pass")

完成 _id 场景:插入一个单词:

mongo.db.passwords.insert( { "_id" : "password" } );

查询看起来像:

mongo.db.passwords.find( { "_id" : request.form["password"] } )

正如@Madarco 提到的,您还可以通过将返回的字段限制为仅 _id 字段({ "_id" : 1})来确保从索引返回结果,从而缩短查询时间。

mongo.db.passwords.find( { "_id" : request.form["password"] }, { "_id" : 1} )

HTH - 罗伯

PS 我不是 Python/Pymongo 专家,所以可能没有 100% 正确的语法。希望它仍然有帮助。

于 2013-05-14T04:34:03.263 回答
2

我会建议检查并尝试 redis 作为一个选项。它很快,非常快,并且有很好的 python 绑定。我会尝试在单词列表的redis中创建一个集合,然后使用该SISMEMBER函数检查该单词是否在集合中。SISMEMBER是一个 O(1) 操作,所以它应该比 mongo 查询快。

那是假设您当然希望整个列表都在内存中,并且您愿意取消 mongo。. .

这是关于 redis 的SISMEMBER的更多信息,以及 redis的python 绑定

于 2013-05-14T04:53:58.767 回答
0

我推荐kyotocabinet,它非常快。我在类似的情况下使用过它:

import kyotocabinet as kyc

from flask import Flask
from flask.views import MethodView
import json

app = Flask(__name__)


dbTree = kyc.DB()

if not dbTree.open('./passwords.kct', DB.OREADER):
    print >>sys.stderr, "open error: " + str(dbTree.error())
    raise SystemExit


app = Flask(__name__)


class HashCheck(MethodView):

  def post(self):
    return json.dumps({'result' : 
      dbTree.check(request.form["password"]) > 0 })
    # Error-handling + test cases to come. Negate is for bool.

  def get(self):
    return redirect('/')

if __name__ == "__main__":
  app.add_url_rule('/api/', view_func=HashCheck.as_view('api'))
  app.run(host="0.0.0.0", debug=True)
于 2013-05-16T01:00:36.690 回答