Neo4j словосочетание запрос - PullRequest
0 голосов
/ 08 ноября 2018

Я создал график Neo4j из Questionnaire завершений, который может иметь 1 или более FreeTextResponse ответов.Каждый FreeTextResponse имеет любое количество Word с.

Word с связано с другими Word с на графике с отношением IS_RELATED_TO, которое имеет свойство similarityValue, обозначающеенасколько похожи слова семантически.

Любое число FreeTextResponse s может быть связано с Word s.

В конечном счете, я хотел бы найти кластеры связанных Questionnaire дополнений на основео сходстве ответов FreeTextResponse.

Мой первый шаг - написать запрос, проходящий через график из узла завершения Questionnaire, через ответы FreeTextResponse, через word s, и через любые FreeTextResponse ответы, что эти Word s также существуют в.

Затем то же самое снова, но делая это через два или более word узлов и вычисляя вес на основе их совокупногозначение сходства.

Структура графика выглядит следующим образом:

enter image description here

Я пробовал несколько подходов, но борюсь сколичество переменных в игре.

MyЛучшая попытка на первом этапе - это:

match (qr:Questionnaire{QuestionnaireReturnID:186406})<-[:IN]-(ftr:FreeTextResponse)<-[:IN]-(w1:WordGraph_Word)-[:IN]->(ftr2:FreeTextResponse)-[:IN]->(qr2:Questionnaire)
WITH qr2, ftr, count(distinct w1) as frequency
WITH distinct qr2, length(split((ftr.fullSentenceString), ' ')) as wordCount, frequency
WITH
COLLECT({
QuestionnaireReturnID: qr2.QuestionnaireReturnID,
frequency: frequency,
wordCount: wordCount,
percentageMatch: (toFloat(frequency) / toFloat(wordCount)) * 100
}) as associatedQuestionnaires
UNWIND(associatedQuestionnaires) as a
WITH a order by a.percentageMatch desc where a.percentageMatch > 15
return a

... но я не уверен, что доверяю результатам и не думаю, что они принимают во внимание, что может быть любое число FreeTextResponse s для Questionnaire.

Каков наилучший подход к решению этой проблемы, пожалуйста?

Спасибо!

Обновление:

Я думаю, что я только что разработал шаг 1, связывая напрямую связанные Questionnaire s следующим образом:

match (qr:Questionnaire{QuestionnaireReturnID:186406})<-[:IN]-(ftr:FreeTextResponse)<-[:IN]-(w:WordGraph_Word)
WITH COLLECT(w) as wordList, count(w) as allWordsInSourceCount
UNWIND(wordList) as words
WITH words, allWordsInSourceCount
MATCH (words)-[relIn:IN]->(ftr2:FreeTextResponse)-[:IN]->(qr2:Questionnaire) WHERE qr2.QuestionnaireReturnID <> 186406
WITH qr2, count(distinct words) as matchFrequency, allWordsInSourceCount
WITH qr2, matchFrequency, allWordsInSourceCount, (toFloat(matchFrequency) / toFloat(allWordsInSourceCount)) * 100 as percentageMatch
WITH qr2, matchFrequency, allWordsInSourceCount, percentageMatch order by percentageMatch desc where percentageMatch > 30
RETURN qr2.QuestionnaireReturnID, matchFrequency, allWordsInSourceCount, percentageMatch

1 Ответ

0 голосов
/ 09 ноября 2018

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

TF-IDF

Подсчет похожих слов в общем случае приведет к плохим результатам. В области поиска информации распространенным методом измерения сходства на основе слов является TF / IDF:

Мера проста, TF - это термин частота в конкретном документе. Есть несколько вариантов, но давайте возьмем простую, частоту терминов для данного предложения: Today I went to the shopping center and then went back to home

TF для слова shopping равен единице, а для to - 2.

Частота обратных документов (IDF) определяет значение этого слова:

idf(word, document) = log ( total number of documents / number of documents containing that word )

TF-IDF рассчитывается как

tf-idf(word, document, corpus) = tf(word, doc) . idf(word, corpus)

Таким образом, слово в конкретном документе будет иметь больший tf-idf, если tf высокий, а idf низкий.

Теперь вернемся к вашему варианту использования, сравнивая два FreeTextResponse, вы также можете вычислить, насколько tf-idf общих слов закрыт друг для друга:

FTR => FreeTextResponse

similarity(ftr1, ftr2, wordA) = 1 - ( tf-idf(wordA, ftr1) - tf-idf(wordA, ftr2) )

Небольшое объяснение на английском языке: если у меня есть документ, где dog появляется 12 раз, и другой документ, где он появляется 1 раз, то эти два документа, возможно, не говорят об одном и том же.

Обратите внимание, что мы обычно используем вариант TF / IDF с учетом длины документа, более подробную информацию можно найти по ссылке в Википедии.

* Игнорируемые слова 1046 *

Во-вторых, не все слова имеют смысл. Это то, что мы называем stopwords, и они могут быть отброшены во время сопоставления сходства или даже не вставлены в график вообще. Эти слова, например, для: the, it, a,...

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

static {
    final List<String> stopWords = Arrays.asList(
      "a", "an", "and", "are", "as", "at", "be", "but", "by",
      "for", "if", "in", "into", "is", "it",
      "no", "not", "of", "on", "or", "such",
      "that", "the", "their", "then", "there", "these",
      "they", "this", "to", "was", "will", "with"
    );
      ....

Похожие слова

На диаграмме показаны слова, связанные друг с другом отношением SIMILAR_TO с показателем сходства.

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

Заключение

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

Вы также можете взглянуть на некоторые расширения Neo4j, которые могут упростить и улучшить вашу текстовую аналитику, например https://github.com/graphaware/neo4j-nlp

...