Как найти все максимальные клики в Neo4J?

#neo4j #cypher #graph-theory #graph-databases

Вопрос:

У меня есть большой график (миллионы узлов/ребер, никаких параллельных ребер или петель) в моей базе данных neo4j, где узлы представляют людей, а ребра представляют дружбу. Я хочу найти все максимальные клики (рассматривая ребра как неориентированные) по крайней мере k с узлами.

Максимальная клика-это клика, которую нельзя расширить, включив еще одну смежную вершину, то есть она не является подмножеством большей клики

Я заглянул в научную библиотеку графических данных neo4j, но смог найти только алгоритм для треугольных клик. Кроме apoc.algo.cliques того, в apoc v3.5, похоже, есть процедура, но она была отмечена как незавершенная работа. Я не нашел никакого алгоритма клики в последних версиях apoc.

Есть ли какой-нибудь запрос на шифр или плагин neo4j, который мог бы мне помочь? Есть ли другой способ подойти к этому?

Комментарии:

1. Вы смотрели на en.wikipedia.org/wiki/Clique_problem#Algorithms

2. @ravenspoint Да, я это сделал. Но это алгоритмы экспоненциального времени. Я не уверен, что было бы разумно реализовывать их для больших графиков. Я надеялся на какой-нибудь встроенный плагин или запрос, потому что они, как правило, оптимизированы для производительности.

3. Ваша вера в людей, которые программируют библиотеки, действительно очень трогательна.

4. Я довольно новичок в neo4j и не знаю базовой архитектуры. Поэтому я склонен доверять их работе.

5. «Чтобы сохранить уважение к сосискам и библиотекам, нельзя смотреть, как они готовятся». — Бисмарк

Ответ №1:

Есть ли другой способ подойти к этому?

Я бы написал свой собственный код. Поскольку я предпочитаю C , я придумал это:

 void cPathFinder::cliques()
{
    // working copy on input graph
    auto work = myGraph;

    // store for maximal clique collection
    std::vector<std::vector<int>> vclique;

    while (1)
    {
        std::vector<int> clique;

        while (work.nodeCount())
        {
            if (!clique.size())
            {
                // start by moving an arbitrary node to the clique from the work graph
                auto nit = work.nodes().begin();
                clique.push_back(nit->first);
                work.removeNode(nit->first);
                continue;
            }
            bool found = false;

            // loop over nodes remaining in work graph
            for (auto amp;u : work.nodes())
            {
                // loop over nodes in clique
                for (int v : clique)
                {
                    if (work.includes_link(v, u.first) ||
                        work.includes_link(u.first, v))
                    {
                        // found node in work that is connected to clique nodes.
                        // move it to clique
                        clique.push_back(u.first);
                        work.removeNode(u.first);
                        found = true;
                        break;
                    }
                }
                if (found)
                    break;  // found a node to add to clique
            }
            if (!found)
                break;      // no more nodes can be added, the clique is maximal
        }

        if (!clique.size())
            break;          // did not find a clique

        // add to collection of maximal cliques
        vclique.push_back(clique);
    }

    // Display results
    for (auto amp;c : vclique)
    {
        std::cout << "clique: ";
        for (int n : c)
            std::cout << myGraph.name(n) << " ";
        std::cout << "n";
    }
}
 

Для этого ввода

 l 1 5
l 1 3
l 2 8
l 2 6
l 3 1
l 3 7
l 4 8
l 4 6
l 5 1
l 5 7
l 6 4
l 6 2
l 7 3
l 7 5
l 8 2
l 8 2
 

Я получаю этот вывод

clique: 5 1 3 7 clique: 8 2 6 4

Чтобы проверить это, вот что graphViz производит с теми же входными данными

введите описание изображения здесь

Полный код вы можете найти здесь.