Упорядочить результаты по количеству совпадений в свойствах ребер - PullRequest
1 голос
/ 02 апреля 2020

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

Так что в технических словах мне нужно отсортировать пользователей по количеству ребер, у которых есть определенные c значения свойств, я пытался с этим запросом, Я думал, что это должно работать, но это не работает:

   let query = g.V().hasLabel('user');

   let search = __;
   for (const question of searcher.questions) {
      search = search.outE('response')
            .has('questionId', question.questionId)
            .has('answerId', question.answerId)
            .aggregate('x')
            .cap('x')     
   }

   query = query.order().by(search.unfold().count(), order.asc);

Выдает эту внутреннюю ошибку gremlin:

org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet cannot be cast to org.apache.tinkerpop.gremlin.structure.Vertex

Я также пытался с несколькими .by() для каждого вопроса, но результат не упорядочен по количеству совпадений.

Как мне написать этот запрос?

1 Ответ

2 голосов
/ 02 апреля 2020

Когда вы cap() и aggregate(), он возвращает BulkSet, то есть Set, который подсчитывает, сколько раз каждый объект существует в этом Set. Он ведет себя как List, когда вы перебираете его, разворачивая каждый объект соответствующего размера счета. Таким образом, вы получаете ошибку, потому что вывод cap('x') - это BulkSet, а поскольку вы строите search в al oop, вы просто вызываете outE('response') для этого BulkSet, и это неверный синтаксис, такой как has() ожидает график Element, такой как Vertex, как указано в ошибке.

Я думаю, вы бы предпочли что-то более похожее на:

let query = g.V().hasLabel('user').
              outE('response');

let search = [];
for (const question of searcher.questions) {
  search.push(has('questionId', question.questionId).
              has('answerId', question.answerId));
}

query = query.or(...search).
              groupCount().
                by(outV())
              order(local).by(values, asc)

Возможно, у меня не совсем правильный синтаксис javascript (и я использовал синтаксис распространения в моем or(), чтобы просто передать идею о том, что должно произойти), но в основном идея заключается в том, чтобы отфильтровать ребра, соответствующие критериям вашего вопроса, а затем использовать groupCount() для подсчета этих ребер.

Если вам нужно сосчитать пользователей, у которых нет подключения, возможно, вы могли бы переключиться на project() - может быть, например:

let query = g.V().hasLabel('user').
              project('user','count').
                by();

let search = [];
for (const question of searcher.questions) {
  search.push(has('questionId', question.questionId).
              has('answerId', question.answerId));
}

query = query.by(outE('response').or(...search).count()).
              order().by('count', asc);

fwiw, я думаю, вы могли бы рассмотреть другую схему для вашего данные, которые могут сделать этот алгоритм рекомендаций более графоподобным. Можно подумать о том, чтобы сделать вопрос / ответ вершиной (возможно, меткой «qa») и иметь ребра go от вершины пользователя до вершины «qa». Затем пользователи напрямую ссылаются на вопрос / ответы, которые они дали. Вы можете легко увидеть с помощью ребер прямую связь, в которой пользователи дали одинаковую комбинацию вопрос / ответ. Это изменение позволяет выполнять запрос более естественно, когда он задает вопрос: «Какие пользователи ответили на вопросы так же, как и пользователь« А »?»

g.V().has('person','name','A').
  out('responds').
  in('responds').
  groupCount().
  order(local).by(values)

С этим изменением вы можете видеть, что мы можем избавиться от него. мы сами все эти has() фильтры, потому что они неявно подразумеваются "ответными" ребрами, которые кодируют их в сами данные графа.

...