【问题标题】:How to speed up program that finds the shortest path between two wikipedia articles如何加速找到两篇维基百科文章之间最短路径的程序
【发布时间】:2016-11-29 23:12:03
【问题描述】:

我最近编写了一个程序,可以找到两篇维基百科文章之间的最短路径。问题是从页面获取所有链接并将它们放入图表需要很长时间。找到路径是容易的部分。 基本上我在做的是这样的:

startingPage = 'Lisbon'
target = 'Adolf Hitler'
graph = nx.DiGraph()
graph.add_node(startingPage)
found = pages.import_page(graph, startingPage)

while found != True:
    for node in list(graph):
        if graph.out_degree(node) == 0:
            found = pages.import_page(graph, node)
        if found == True:
            break;

而我的 import_page 函数就是这个:

def import_page(graph, starting, target):
    general_str = 'https://en.wikipedia.org/w/api.php?action=query&prop=links&pllimit=max&format=json&titles='
    data_str = general_str + starting
    encoded_data_str = data_str.encode('utf-8') #Sanitize input
    response = url.urlopen(encoded_data_str)
    data = json.loads(response.read())
    pageId = data['query']['pages'].keys()
    print starting
    if data['query']['pages'].keys()[0] == '-1': #Check if the page doesn't exist in Wikipedia
        return False
    elif data['query']['pages'][pageId[0]].keys()[2] != 'links': #Check if the page has no links in it
        return False

    for jsonObject in data['query']['pages'][pageId[0]]['links']:

        graph.add_node(jsonObject['title'])
        graph.add_edge(starting, jsonObject['title'])

        if jsonObject['title'] == target:
            return True

    while data.keys()[0] != 'batchcomplete':

        continueId = data['continue']['plcontinue']
        continue_str = data_str + '&plcontinue=' + continueId
        encoded_continue_str = continue_str.encode('utf-8') #Sanitize input
        response = url.urlopen(encoded_continue_str)
        data = json.loads(response.read())

        for jsonObject in data['query']['pages'][pageId[0]]['links']:
            graph.add_node(jsonObject['title'])
            graph.add_edge(starting, jsonObject['title'])
            if jsonObject['title'] == target:
                return True

    return False

问题在于任何大于 2/3 链接的距离都需要大量时间。关于如何加快速度的任何想法?

【问题讨论】:

  • 为什么要关心边缘?你不想保留一个活动节点列表和一个访问节点列表吗?另一个问题(可能只是由于我不知道图形库引起的):在迭代其节点时修改图形是否有效?
  • 还有,这里的写法,你的import_page真的是import_Adolf_Hitler_page :)
  • 是的,我已经更新了,忘记在这里更新了!
  • @NicoSchertler 好吧,我需要边缘来连接相互链接的页面,对吧?否则我怎么知道两个页面之间有链接?
  • @NicoSchertler 另外,该库不允许修改图形,但这就是我迭代列表(图形)的原因。我创建一个列表只是为了迭代。

标签: python algorithm graph networkx wikipedia-api


【解决方案1】:

我使用了@Tgr 指出的方法,利用了一个小世界。 如果您使用加权网络,您可以将搜索限制为足够大以包含相关中心的子图,并且足够小以在网络 RESTful API 中处理。

您可能想查看 iGraph 模块而不是 networkx,以减少内存占用。

通过我向您建议的方法,我已经能够获得连接最多 5 条查询的维基百科文章的最短路径,实时创建的子图的内存占用量高达 100MB。两个主题之间的最短路径不到 1 秒。

我很乐意分享一个指向我的项目的链接,该链接实际上为维基百科计算加权知识网络,以允许搜索多个主题之间的联系——它会违反 SO 政策还是可能对 OP 和讨论他的问题有用问题?

编辑


感谢@Tgr 对政策的汇报。

Nifty.works是一个原型平台,用于搜索跨学科领域之间的联系。 知识图谱是与英语维基百科配对的维基数据的子集。

作为 OP 的示例,此示例显示了 五篇维基百科文章之间查询的最短路径subgraph for connections between articles: "Shortest Path Problem", "A star search", "networkx", "knowledge graph" and "semantic network"

我将维基百科的知识图谱计算为加权网络。 该网络具有小世界属性。 通过划分知识图(子图)的一部分来查询文章之间的连接(路径)。

使用这种方法,即使在小型服务器机器上,也可以足够快地提供图形搜索以提供知识发现方面的见解。

在这里你可以找到英文维基百科的examples of gamification of shortest paths between two articles,每对的距离大于 3 个链接——也就是说,它们不是第一邻居:例如“机器学习”和“生活”-here a json of the queried subgraph)。

您甚至可能想要添加参数来调整加权子图的大小,从而获得不同的结果。 举个例子,看看两者之间的区别:

最后,也看看这个问题:https://stackoverflow.com/a/16030045/305883

【讨论】:

  • 分享您自己的作品并在涉及主题时明确披露绝对符合 SO 政策。 (See FAQ.)
  • 感谢您的详细解答!
【解决方案2】:

使用简单的算法和 Web API 几乎不可能确定地找到最短路径。如果最短路径有 N 步,您需要走完所有长度为 N-1 或更短的可能路径才能确定。有数百万篇文章和几十到数百个链接,除非你真的很幸运,而且最短的路径只有 1-2 个链接,否则这是不可行的。如果说在 10 步之外,您将不得不提出数十亿次请求,这需要数年时间。

如果您只是想在大多数情况下找到一条相当短的路径,您可以尝试类似A* search algorithm 之类的具有良好启发式的方法。例如,您可以假设某种small-world property 并尝试识别与其他主题中心以及该主题中的所有文章接近的主题中心。或者,您可以根据与目标主题相同或历史时期相同的候选人评分。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-22
    相关资源
    最近更新 更多