« Последняя миля » — это термин, используемый в телекоммуникационной отрасли, который относится к предоставлению возможности подключения клиентам, которые фактически будут использовать систему. В смысле баз данных графов, это относится к тому, насколько хорошо конечный пользователь может извлечь ценность и понимание из графика. Мы уже видели пример этой концепции с Graph Search , позволяющей пользователю выражать свои запросы на естественном языке. Сегодня мы увидим еще один пример. Мы будем использовать возможности Neo4j 2.0, чтобы сделать эту работу, поэтому обязательно прочитайте предыдущий пост по этому вопросу.
Мы собираемся использовать VisualSearch.js, созданный Сэмюэлем Клэем из NewsBlur . VisualSearch.js расширяет возможности обычных окон поиска с помощью автозаполнения многогранных поисковых запросов. Это довольно легко настроить, и есть аннотированное описание доступных опций. Вы можете увидеть, что он делает на изображении ниже, или щелкните по нему, чтобы попробовать их демо.
Ранее мы подготовили график Neo4j 2.0, в котором актеры, режиссеры, продюсеры, писатели и пользователи подключены к фильмам.
Первое, что нам нужно сделать, это найти Facets для visualsearch.js. Мы не хотим настраивать это вручную, потому что это будет болезненно, и наш график может со временем измениться. Поэтому вместо этого мы будем использовать метод list_labels, чтобы получить метки нашего графика:
get '/facets' do content_type :json cache_control :public, :max_age => 600 facets = [] categories = $neo.list_labels categories.each do |cat| get_properties(cat).each do |label| facets << {:category => cat, :label => cat + "." + label} end end facets.to_json end
Одна из приятных вещей, которые мы можем сделать, это сгруппировать свойства метки вместе, у нас нет сложной схемы того, какие свойства есть в каждой метке, но мы можем запросить график, получить один узел и посмотреть свойства, которые у него есть.
def get_properties(category) cypher = "MATCH n:#{category} RETURN n LIMIT 1" $neo.execute_query(cypher)["data"].first.first["data"].keys end
Это вернет массив JSON, который выглядит следующим образом:
[{"category":"Writer","label":"Writer.born"}, {"category":"Writer","label":"Writer.name"}, {"category":"Actor","label":"Actor.born"}, {"category":"Actor","label":"Actor.name"} ...
Мы передадим это в visualsearch.js, и наш первый выпадающий список будет работать с этими сгруппированными свойствами меток.
Как только пользователь щелкнет по одному из свойств, мы заполним некоторые из доступных параметров для этого свойства. Мы можем сделать это с помощью cypher, сопоставив узлы указанной метки, которые имеют свойство, о котором мы заботимся, и сгруппировав его так, чтобы мы получили только первые 25 уникальных значений.
get '/values/:facet/' do content_type :json label, key = get_label_and_key(params) cypher = "MATCH node:#{label} WHERE HAS(node.#{key}) RETURN node.#{key} AS label, COUNT(*) ORDER BY label LIMIT 25" $neo.execute_query(cypher)["data"].collect{|x| x.first.to_s}.compact.flatten.to_json end
Теперь мы можем увидеть некоторые значения в нашем окне поиска. В этом примере мы собираем имена актеров в нашем графе.
Лучшие 25 предметов — это хорошо, но что, если мы ищем актера, чьи имена с буквой Z похожи на « Зак Гренье »? Visualsearch.js дает нам возможность начать вводить значение и сбросить наши параметры для соответствия.
Мы расширим наш предыдущий запрос, добавив регистрозависимое регулярное выражение с термином или частью искомого термина.
get '/values/:facet/:term' do content_type :json label, key = get_label_and_key(params) cypher = "MATCH node:#{label} WHERE HAS(node.#{key}) AND node.#{key} =~ {term} RETURN node.#{key} AS label, COUNT(*) ORDER BY label LIMIT 25" $neo.execute_query(cypher, {:term => "(?i).*" + params[:term] + ".*"})["data"].collect{|x| x.first.to_s}.compact.flatten.to_json end
Как только мы нажимаем на Зак Гренье, происходит несколько вещей. Мы получаем небольшое сообщение о том, что:
Вы искали: Actor.name: «Зак Гренье». (1 узел)
Наша панель поиска снова оживает со следующим набором меток для запроса…
… И наш график (в настоящее время состоящий только из одного узла) заполняется с помощью vivagraph.js. См. Этот предыдущий пост vivagraph.js для получения дополнительной информации о том, как работает эта великолепная библиотека визуализации графиков.
Теперь … я знаю, что вы можете подумать … мы заполнили узел актера, и теперь в нашем раскрывающемся списке доступен только фильм. Как это произошло? Это магия этого приложения. Вместо случайного захвата любого следующего узла, мы берем контекст нашего первого узла и строим путь доступных соединений оттуда. Если мы нажимаем «Movie.title», мы вызываем следующий метод под обложками, чтобы получить наши возможности:
post '/connected_values/:facet/' do content_type :json related_label, related_key = get_label_and_key(params) match, where, values = prepare_query(params) last_node = get_last_node_id(params) where.pop where << "HAS(node#{last_node}.#{related_key})" cypher = prepare_cypher(match,where) cypher << "WITH LAST(EXTRACT(n in NODES(p) : n.#{related_key}?)) AS label, COUNT(*) AS cnt " cypher << "RETURN label ORDER BY label LIMIT 25" parameters = prepare_parameters(values) $neo.execute_query(cypher, parameters)["data"].flatten.collect{|d| d.to_s}.to_json end
Это выглядит немного сложно, но все, что мы делаем, это просто динамически создаем запрос шифрования, который в итоге будет выглядеть так:
MATCH p = node0:Actor -- node1:Movie WHERE node0.name? = {value0} AND HAS(node1.title) WITH LAST(EXTRACT(n in NODES(p) : n.title?)) AS label, COUNT(*) AS cnt RETURN label ORDER BY label LIMIT 25
Этот Cypher-запрос будет выполнен с параметрами {«value0 ″ =>« Zach Grenier »}. Он найдет узел Actor для Zach Grenier на графике, а затем найдет узлы с надписью «Movie», связанные с Zach Grenier, и затем извлечет свойство «title» из последнего узла на нашем пути (который случается с быть в фильмах, в которых участвует Зак Гренье, и дать нам наш ответ.
На нашем графике у нас есть только две вещи, связанные с Заком Гренье: фильм «RescueDawn» и «Twister». Давайте продолжим и нажмем на Twister:
Мы запрашиваем график с шаблоном «Актер по имени Зак Гренье», который связан с фильмом «Твистер». Граф находит этот шаблон, возвращает узлы и отношения в этом шаблоне, и Twister добавляется к нашему графику, связанному с Заком Гренье.
Например, шаблоны, которые мы можем создать, могут выходить за рамки одного прыжка. Актер 1929 года рождения, который снимался в «Снегу на кедрах» вместе с Риком Юном, который также был в «Ниндзя-ассасине», вместе с другими актерами…
MATCH p = node0:Actor -- node1:Movie -- node2:Actor -- node3:Movie -- node4:Actor WHERE node0.born? = {value0} AND node1.title? = {value1} AND node2.name? = {value2} AND node3.title? = {value3} AND HAS(node4.name) WITH LAST(EXTRACT(n in NODES(p) : n.name?)) AS label, COUNT(*) AS cnt RETURN label ORDER BY label LIMIT 25"
Этот запрос будет выполнен с параметрами: {«value0 ″ => 1929,« value1 ″ => «Снег на кедрах», «value2 ″ =>« Рик Юн »,« value3 ″ => «Убийца ниндзя»}}. Один из актеров в конце паттерна — «Наоми Харрис», и как только мы нажимаем на нее, мы получаем этот график:
Не просто поверь мне на слово, подумал. Попробуйте демо-версию , посмотрите на исходный код и наведите на него свой собственный маркированный график Neo4j 2.0.
Чего не хватает?
Это динамический интерфейс, который дает конечному пользователю быстрый доступ к графику. Однако проницательный наблюдатель заметит, что чего-то не хватает. Типы отношений. Шаблоны, которые мы создаем и сопоставляем с графом, заботятся только о связанных узлах, а не о том, как они связаны, и это может быть очень важной особенностью нашего графа, который мы опускаем. Увы, этот маленький проект — не последняя миля, он всего лишь на шаг впереди, и в итоге мы его достигнем.
Помоги мне работать над проблемами такого рода.
Понимание мощностей графиков даст толчок вашим навыкам архитектора данных. Не позволяйте этому сообщению в блоге быть последним разом, когда вы думаете о графиках. Узнайте о графиках на одном из десятков событий, уже находящихся в Календаре, и следите за тем, как все больше и больше добавляются каждую неделю. Потратьте некоторое время, чтобы посмотреть эти отличные графические видео о событиях, которые вы могли пропустить. Прочитайте книгу «Базы данных графиков» и, конечно… подпишитесь на мой блог и следуйте за мной в Twitter.