Как найти одинаковые значения в разных полях в Elasticsearch через Python Query? - PullRequest
0 голосов
/ 27 января 2019

У меня есть значения в Elasticsearch (+ Kibana) и я хочу создать график, в котором соединены определенные узлы.

Моими полями являются «prev» и «curr», и они указывают «предыдущую» и «текущую» страницы, которые посетил пользователь.

например:

  • пред .: Main_Page, curr: Donald_Trump
  • пред .: другое-внутреннее, курс: El_Bienamado
  • ...

Итак, я пытаюсь найти значения, где ток равен предыдущему, чтобы иметь возможность соединить их и визуализировать через Networkx-Graph в Кибане.

Моя проблема в том, что я только вчера начал с синтаксиса запроса и не знаю, возможно ли это вообще. В общем, моя цель - создать график, в котором узлы связаны с цепочкой, например:

  • Main_Page -> Donald_Trump -> Проблемы_в_Африке -> и т. Д.

Это означает, что кто-то посетил эти страницы в определенном порядке.

Сейчас я пробовал:

def getPrevList():
    previous = []
    previousQuery = {
        "size": 0,
        "aggs": {
            "topTerms": {
                "terms": {
                    "field": "prev",
                    "size": 50000
                }
            }
        }
    }
    results = es.search(index="wiki", body=previousQuery)["aggregations"]["topTerms"]["buckets"]
    for bucket in results:
        previous.append({
            "prev" : bucket["key"],
            "numDocs" : bucket["doc_count"]
        })
    return previous

prevs=getPrevList()

rowNum = 0;
totalNumReviews=0

for prevDetails in prevs:
    rowNum += 1
    totalNumDocs += prevDetails["numDocs"]
    prevId = prevDetails["prev"]

    q = {
        "query": {
            "bool": {
                "must": [
                    {
                        "term": {"prev": prevId}
                    }
                ]
            }
        },
        "controls": {
            "sample_size": 10000,
            "use_significance": True
        },
        "vertices": [
            {
                "field": "curr",
                "size": VERTEX_SIZE,
                "min_doc_count": 1
            },
            {
                "field": "prev",
                "size": VERTEX_SIZE,
                "min_doc_count": 1
            }
        ],
        "connections": {
            "query": {
                "match_all": {}
            }
        }
    }

В конце я делаю следующее:

results = es.transport.perform_request('POST', "/wiki/_xpack/_graph/_explore", body=q)  

# Use NetworkX to create a graph of prevs and currs we can analyze
G = nx.Graph()

for node in results["vertices"]:
    G.add_node(nodeId(node), type=node["field"])

for edge in results["connections"]:
    n1 = results["vertices"][int(edge["source"])]
    n2 = results["vertices"][int(edge["target"])]
    G.add_edge(nodeId(n1), nodeId(n2))

Я скопировал его из другого примера, который хорошо работал, но я вижу, что "соединения" важны для возможности соединения вершин.

Насколько я понял, мне нужен запрос, чтобы найти правильное поле "prev". Элементы управления не имеют значения на данный момент. И вот для меня наступает сложная часть: что я пишу в части вершин и связей? Верно ли, что я определил вершины как поля prev и curr? И в запросе соединений: на данный момент я определил «match_all», но это, очевидно, не правильно. Мне нужен запрос, где я могу «сопоставить» те, где prev равно curr и соединить их .. но КАК ??

Любая подсказка приветствуется! Спасибо вперед.

EDIT

Как и предложил @Lupanoide, я изменил код и теперь имею две визуализации: первое - первое предложенное решение, и оно дает мне этот график (часть его) (matplotlib, но не Kibana):

dict2Graph

Второе решение выглядит более сумасшедшим и, скорее всего, будет правильным, но мне нужно сначала визуализировать его в Кибане:

two for-loops

Итак, новый конец моего сценария теперь:

gq = json.dumps(q)

workspaceID ="/f44c95c0-223d-11e9-b49e-bb0f8e1e7bae" # my v6.4.0 workspace

workspaceUrl = "graph#/workspace/"+workspaceID+"?query=" + urllib.quote_plus(gq)        
doc = {
    "url": workspaceUrl
}
res = es.index(index=connectionsIndexName, doc_type='task', id=0, body=doc)

Моя единственная проблема сейчас в том, что когда я использую Kibana для открытия URL, я не вижу график. Вместо этого я получаю страницу «Новый график».

EDIT2 Хорошо, я отправляю запрос, но, конечно, одного запроса недостаточно. Мне нужно передать график и его связи, верно? Возможно ли это?

Большое спасибо!

1 Ответ

0 голосов
/ 27 января 2019

РЕДАКТИРОВАТЬ: Для вашего случая использования вам нужно найти все значения для поля curr с тем же значением prev.Таким образом, вам нужно сгруппировать все страницы, на которые нажимают после определенной страницы.Вы можете сделать это с условиями агрегации .Вам необходимо создать запрос, который, с одной стороны, возвращает с агрегацией термина все значения для поля prev, а затем вы агрегируете по всем сгенерированным значениям curr:

def getOccurrencyDict():

  body = {
  "size": 0,
  "aggs": {
    "getAllThePrevs": {
      "terms": {
        "field": "prev",
        "size": 40000
      },
      "aggs": {
        "getAllTheCurr": {
          "terms": {
            "field": "curr",
            "size": 40000
          }
        }
      }
    }
  }
}
result = es.search(index="my_index", doc_type="mydoctype", body=body)

ЗатемВы должны построить структуру данных, которую принимает библиотека class Graph() из Networkx.Таким образом, вы должны создать dict списка и затем передать эту переменную методу fromdictoflist :

dict2Graph = dict()
for res in result["aggregations"]["getAllThePrevs"]["buckets"]:
    dict2Graph[ res["key"] ] = list() #you create a dict of list with a prev value key
    dict2Graph[ res["key"] ].append(res["getAllTheCurr"]["buckets"]) # you append a list of dict composed by key `key` with the `curr` value, and key `doc_count` with the number of occurrence of the term `curr` before the term prev

Теперь вы передаете его методу приема networkx:

G=nx.from_dict_of_lists(dict2Graph)

Я не тестировал проглатывание networkx, поэтому, если оно не работает, это потому, что мы передали внутри него диктовку списка диктов, а не списков, поэтому вам следует немного изменить способ построения вашей dict2Graph dict

Если агрегирование запроса агрегации происходит слишком медленно, следует использовать prtition. Прочтите здесь , как вы можете достичь агрегации разделов в эластичном

РЕДАКТИРОВАТЬ:

после прочтения документации по NetworkX, вы также можете сделать это, не создаваяпромежуточная структура данных:

from elasticsearch import Elasticsearch
from elasticsearch.client.graph import GraphClient

es = Elasticsearch()
graph_client = GraphClient(es) 

def createGraphInKibana(prev):
    q = {
    "query": {
        "bool": {
            "must": [
                {
                    "term": {"prev": prev}
                }
            ]
        }
    },
    "controls": {
        "sample_size": 10000,
        "use_significance": True
    },
    "vertices": [
        {
            "field": "curr",
            "size": VERTEX_SIZE,
            "min_doc_count": 1
        },
        {
            "field": "prev",
            "size": VERTEX_SIZE,
            "min_doc_count": 1
        }
    ],
    "connections": {
        "query": {
            "match_all": {}
          }
       }
    }
    graph_client.explore(index="your_index", doc_type="your_doc_type", body=q)





G = nx.Graph()
for prev in result["aggregations"]["getAllThePrevs"]["buckets"]:
    createGraphInKibana(prev['key'])
    for curr in prev["getAllTheCurr"]["buckets"]:
        G.add_edge(prev["key"], curr["key"], weight=curr["doc_count"])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...