图数据库Neo4J 中文分词查询及全文检索(建立全文索引)

Neo4j的全文索引是基于Lucene实现的,但是Lucene默认情况下只提供了基于英文的分词器,下篇文章我们在讨论中文分词器(IK)的引用,本篇默认基于英文分词来做。我们前边文章就举例说明过,比如我要搜索苹果公司?首先我们要做的第一步在各个词条上创建全文索引,第二步我们根据苹果公司进行全文检索,把匹配度高的按顺序输出。下边我们一步步讲解怎么做。

# Neo4j的全文索引采用Lucene,能够对neo4j中string类型的属性建立全文索引。

- 1. 能够同时为node和relationship的属性建立索引。而neo4j内嵌的索引仅能够对node的属性建立索引。
- 2. 至于字符串如何被切分和索引,取决于为lucene配置的analyzer。支持自定义Analyzer,包括lucene中没有提供的。
- 3. 能够用lucene查询语句进行查询;
- 4. 能够返回相似度score;
- 5. 能够随着节点和关系的添加、移除、修改进行自动的更新;
- 6. 自动检查一致性,如果有不一致的问题自动重建;
- 7. 在单个索引中,能够支持任意数目的文档;
- 8. 创建、删除、更新都是事务的,能够在集群中自动进行副本;
- 9. 能够通过cypher语句访问.
- 10. 能够配置为满足最终一致性。即,索引更新在提交路径中被移除,转为后台线程。利用此特性,对于性能要求高的场景,能够消除主要的写瓶颈。

# 相比于Neo4j内嵌的索引,采用Lucene索引具有如下优势:

- 1. neo4j的内嵌索引采用b树,其仅能够对STARTS WITH、ENDS WITH、完全相等三种条件起作用。而lucene建立的全文索引能够对任意片段的字符串进行查询。
- 2. lucene索引能够对多个label建立.
- 3. lucene索引能够对一到多个关系建立.
- 4. 能够同时应用于多个属性。与内嵌索引的Composite Index不同。Composite Index仅对满足label且同时具有所有属性的实体起作用,而全文索引则对至少满足一个label、关系类型、属性的节点或关系起作用.

1. call和yield的用法

首先看看这两个词的用方法。CALL语句用于调用数据库中的过程(Procedure),YIELD子句用于显示的选择返回结果集中的哪些部分并绑定到一个变量以供后续查询引用。简单说就是用call来调用函数,用yield来接收函数返回的结果。我们举个例子

call db.labels() yield label
return count(label) as num

这里是调用数据库中内嵌的过程db.labels()计算数据库中的总标签数。返回结果

2. 索引

在Neo4j中,有两种不同的索引类型:B-树和全文索引

可以使用Cypher创建和删除B-树索引。用户通常不必知道索引就可以使用它,因为Cypher的查询计划器会决定在哪种情况下使用哪个索引。B-树索引擅长于对所有类型的值进行精确查找,以及范围扫描,完整扫描和前缀搜索。比如(=,>,start with,contains)等

全文索引与B-树索引不同,它们针对索引和搜索文本进行了优化。它们用于需要理解语言的查询,并且仅索引字符串数据。还必须通过过程明确查询它们。全文索引需要手动去创建它,查询的时候也是手动去调用。

在理解了索引的两种概念后,我们着手看看全文索引怎么创建。

3. 创建全文索引

在第一节中用到了db.labels()的过程,那有没有内置创建全文索引的过程呢。答案当然是有了。会发现有db.index.fulltext.createNodeIndex(),那就用这个过程来开始创建一个全文索引。在Dao层代码如下,其中创建索引的名称,标签和字段通过动态传参传过去的,比如在公司,产品上创建公司名称,产品名称的全文索引名称为allFullIndex

可以手动从CQL查询界面进行创建

比如从GoodDes标签的name上创建全文索引, 并使用cjk分词器

CALL db.index.fulltext.createNodeIndex("FT_GOODDES",["GoodDes"],["name"],{analyzer:"cjk", eventually_consistent:"true"})

CALL db.index.fulltext.queryNodes("FT_GOODDES", "气体导流管(旧)") YIELD node, score
WHERE score > 0.6
MATCH (node)-[:GoodAndCode]->(goodCode:GoodCode)
RETURN ID(node) AS nodeId, node.name AS goodDesName, score, ID(goodCode) AS goodCodeId, goodCode.code AS goodCodeCode;

@Repository
public interface FullIndexRepository extends Neo4jRepository<CompanyEntryNode, String> {
    /**
     * 创建索引
     *
     * @param indexName  索引名称
     * @param labels     标签名称
     * @param properties 属性
     */
    @Query("call db.index.fulltext.createNodeIndex({indexName},{labels},{properties})")
    void createFullIndex(String indexName, String[] labels, String[] properties);

    /**
     * 删除索引
     *
     * @param indexName 索引名称
     */
    @Query("call db.index.fulltext.drop({indexName})")
    void deleteFullIndexByName(String indexName);
}

service层和controller层就不写了,直接调用我们创建的过程,就成功创建了一个名称为allFullIndex的全文索引。

在这里插入图片描述

4. 查询索引

同样的有创建索引的过程,也有查询全文索引的过程db.index.fulltext.queryNodes(),那我们在dao层做如下定义。这里结果中返回了node和score。score就是按照相似度给出的一个分值,分词器会影响这个分值,node就是创建索引的节点信息。结果默认是按照score数值从高到低返回。


@Repository
public interface BaseSearchRepository extends Neo4jRepository<CompanyEntryNode, String> {

    /**
     * 查询全文检索数据
     *
     * @param searchWord
     * @return
     */
    @Query("call db.index.fulltext.queryNodes('allFullIndex',{searchWord}) yield node,score " +
            "return node.name as name,score")
    List<BaseSearchDto> fullTextSearch( String searchWord);
    }

在controller层中我们调用会返回如下结果

在这里插入图片描述

这样整个全文索引的创建和查询就完成了。

5. 其他调用过程 [一]

db.index.fulltext.drop()

描述删除指定的索引。
用法db.index.fulltext.drop(indexName :: STRING?) :: VOID

db.index.fulltext.createNodeIndex()

描述为给定的标签和属性创建节点全文索引。可选的“ config”映射参数可用于为索引提供设置。支持的设置是“分析器”,用于指定在建立索引和查询时要使用的分析器。使用以下db.index.fulltext.listAvailableAnalyzers步骤查看可用的选项。可以将’eventually_consistent’设置为’true’,以使该索引最终保持一致,从而将来自提交事务的更新应用于后台线程。
语法db.index.fulltext.createNodeIndex(indexName :: STRING?, labels :: LIST? OF STRING?, properties :: LIST? OF STRING?, config = {} :: MAP?) :: VOID

db.index.fulltext.createRelationshipIndex()

描述查询给定的全文索引。返回匹配关系及其Lucene查询分数,按分数排序。选项映射的有效键是:'skip’跳过前N个结果;'limit’限制返回的结果数。
用法`db.index.fulltext.queryRelationships(indexName :: STRING?, queryString :: STRING?, options = {} :: MAP?) :: (relationship :: RELATIONSHIP?, score :: FLOAT?)```

db.index.fulltext.queryRelationships()

描述为给定的关系类型和属性创建一个关系全文本索引。可选的“ config”映射参数可用于为索引提供设置。支持的设置是“分析器”,用于指定在建立索引和查询时要使用的分析器。使用以下db.index.fulltext.listAvailableAnalyzers步骤查看可用的选项。可以将’eventually_consistent’设置为’true’,以使该索引最终保持一致,从而将来自提交事务的更新应用于后台线程。
用法db.index.fulltext.createRelationshipIndex(indexName :: STRING?, relationshipTypes :: LIST? OF STRING?, properties :: LIST? OF STRING?, config = {} :: MAP?) :: VOID

db.index.fulltext.queryNodes()

描述查询给定的全文索引。返回匹配的节点及其Lucene查询分数,按分数排序。选项映射的有效键是:'skip’跳过前N个结果;'limit’限制返回的结果数。
用法db.index.fulltext.queryNodes(indexName :: STRING?, queryString :: STRING?, options = {} :: MAP?) :: (node :: NODE?, score :: FLOAT?)

db.index.fulltext.listAvailableAnalyzers()

描述列出可以配置全文本索引的可用分析器。
用法db.index.fulltext.listAvailableAnalyzers() :: (analyzer :: STRING?, description :: STRING?, stopwords :: LIST? OF STRING?)

6. 其他调用过程 [二]

https://blog.csdn.net/xiaqingyin/article/details/105567306

在这里插入图片描述

7. 举例 - 创建和配置、查询、删除全文索引

使用全文索引进行创建

例如,想要对于Label为Movie和Book的节点创建索引,索引的字段包括title和description。则采用如下cypher语句。

CALL db.index.fulltext.createNodeIndex("titlesAndDescriptions",["Movie", "Book"],["title", "description"])

想要使用以上索引搜索标题或者描述中包含“matrix”的节点,调用如下cypher语句。

CALL db.index.fulltext.queryNodes("titlesAndDescriptions", "matrix") YIELD node, score
RETURN node.title, node.description, score

创建关系索引,以及可选参数config的使用。

CALL db.index.fulltext.createRelationshipIndex("taggedByRelationshipIndex",["TAGGED_AS"],["taggedByUser"], { analyzer: "url_or_email", eventually_consistent: "true" })

使用全文索引进行查询

CALL db.index.fulltext.queryNodes("titlesAndDescriptions", "Full Metal Jacket") YIELD node, score
RETURN node.title, score

可以用Lucene的全文检索语法,例如,如果需要完全匹配,则加双引号

CALL db.index.fulltext.queryNodes("titlesAndDescriptions", "\"Full Metal Jacket\"") YIELD node, score
RETURN node.title, score

可以使用逻辑操作符,例如AND OR

CALL db.index.fulltext.queryNodes("titlesAndDescriptions", 'full AND metal') YIELD node, score
RETURN node.title, score

还可以对指定的属性进行查询。

CALL db.index.fulltext.queryNodes("titlesAndDescriptions", 'description:"surreal adventure"') YIELD node, score
RETURN node.title, node.description, score

删除全文索引

CALL db.index.fulltext.drop("taggedByRelationshipIndex")

8. 全文检索之中文分词器

其实用了这么久,我感觉用不用中文的全文索引影响不是很大

说说二种方式实现中文全文索引的创建。

1). 利用系统自带的分词器

我们在创建全文索引函数的时候是可以指定索引的分词器的,他的分词器可用下边的方式查询:

call db.index.fulltext.listAvailableAnalyzers

在这里插入图片描述

查到很多系统自带的分词器,其中有一个是“cjk”是针对中国,日本,韩国做的分词器,所以说是支持中文分词的。所以可以这样建索引,像下边指定analyzer的类型为“cjk”就指定的分词器的类型。

CALL db.index.fulltext.createNodeIndex("companyFullIndex",["CompanyEntry"],["name"], { analyzer: "cjk"}

2). 通过第三方库来创建全文索引

参考https://zhuanlan.zhihu.com/p/364927850

未验证

通过查找有第三方库neo4j-graph-plugin-1.0.1.jar,这个不确定是不是官方的还是别人提供的,git下载地址:

https://github.com/crazyyanchao/ongdb-lab-apoc

下载neo4j-graph-plugin-1.0.1.jar文件,放到neo4j的plugins目录下,该插件对应的ik版本为:IKAnalyzer-5.0,支持LUCENE-5.5.0。修改配置文件,然后重启neo4j服务。

dbms.security.procedures.unrestricted=apoc.*,zdr.*

安装好后执行,如果不报错,表示安装成功。初次会失败!

RETURN zdr.apoc.hello("你好") as greeting

运行函数zdr.index.iKAnalyzer会报莫名其妙的错误,经过测试需要继续从https://github.com/crazyyanchao/neo4j-graph-plugin下载neo4j-graph-plugin-master.zip文件,解压缩后取出其中的dic目录拷贝到neo4j根目录下,否则一直运行失败,因为他需要找分词文件目录,和java中引用IK分词一样。dic目录下的分词文件user_defined.dic可以添加自定义的分词。如果想修改用户自定义词典的位置,可以修改配置文件:

vim dic/dic-cfg/IKAnalyzer.cfg.xml

在这里插入图片描述

以上配置好了之后创建中文索引,CompanyFullIndex是索引名称,CompanyEntry是节点。

CALL zdr.index.addChineseFulltextIndex('CompanyFullIndex', ["name"], 'CompanyEntry') YIELD message RETURN message

这里的语法和系统库里的稍微参数位置不一样,其他逻辑都是一样的。查询的方法如下。

CALL zdr.index.chineseFulltextIndexSearch('CompanyFullIndex', 'name:测试~') YIELD node RETURN node

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/157692.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

低代码是“银弹”,还是“毒弹”?

目录 1.Pro Code 真的更“香”吗&#xff1f; 门槛高 跨界难 代码编写只是第一步 2.Low Code 银弹论合理吗&#xff1f; Pro Code和Low Code的差异&#xff1a; 3.写在最后 “低代码”接力“中台”燃起了熊熊之火&#xff0c;引发了众多业内人士论战。有人认为低代码是毒瘤&…

苍穹外卖--新增员工

请求方式Post,请求参数&#xff1a; 用EmployeeDTO类接收参数 Controller层实现&#xff1a; PostMappingpublic Result save(RequestBody EmployeeDTO employeeDTO){employeeService.save(employeeDTO);return Result.success();}service层实现&#xff1a; Overridepublic …

竞赛选题 深度学习验证码识别 - 机器视觉 python opencv

文章目录 0 前言1 项目简介2 验证码识别步骤2.1 灰度处理&二值化2.2 去除边框2.3 图像降噪2.4 字符切割2.5 识别 3 基于tensorflow的验证码识别3.1 数据集3.2 基于tf的神经网络训练代码 4 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x…

kubernetes学习-概念3

工作负载资源 Kubernetes 提供了几个内置的 API 来声明式管理工作负载及其组件。 最终&#xff0c;你的应用以容器的形式在 Pods 中运行&#xff1b; 但是&#xff0c;直接管理单个 Pod 的工作量将会非常繁琐。例如&#xff0c;如果一个 Pod 失败了&#xff0c;你可能希望运行…

水厂消毒的设施设备有哪些

水厂消毒的设施设备主要包括以下几种&#xff1a; 紫外线消毒器&#xff1a;利用紫外线辐射破坏微生物DNA的复制和细胞分裂功能&#xff0c;达到杀灭微生物的目的。紫外线消毒器具有操作简便、效果明显、净化速度快等优点&#xff0c;广泛应用于家庭、学校、饮用水生产企业等场…

振弦传感器表面钢筋计与振弦采集仪组成岩土工程安全监测

振弦传感器表面钢筋计与振弦采集仪组成岩土工程安全监测 振弦传感器表面钢筋计和振弦采集仪可以组成岩土工程安全监测系统&#xff0c;用于监测结构物或岩土体的振动和应变变化情况。具体可以实现以下功能&#xff1a; 1. 振动监测&#xff1a;振弦传感器可以实时监测结构物或…

【数据结构】树与二叉树(十八):树的存储结构——Father链接结构、儿子链表链接结构

文章目录 5.1 树的基本概念5.1.1 树的定义5.1.2 森林的定义5.1.3 树的术语 5.2 二叉树5.3 树5.3.1 树的存储结构1. 理论基础2. 典型实例 5.3.2 Father链接结构a. 定义树节点结构b. 创建新节点c. 主函数d. 代码整合 5.3.3 儿子链表链接结构a. 定义树节点结构b. 创建新节点c. 添加…

cocos----刚体

刚体&#xff08;Rigidbody&#xff09; 刚体&#xff08;Rigidbody&#xff09;是运动学&#xff08;Kinematic&#xff09;中的一个概念&#xff0c;指在运动中和受力作用后&#xff0c;形状和大小不变&#xff0c;而且内部各点的相对位置不变的物体。在 Unity3D 中&#xff…

2023 OceanBase 年度发布会:砥砺自研,为“关键业务负载”打造一体化数据库

11 月 16 日&#xff0c;2023 OceanBase 年度发布会在京顺利召开。在本次发布会上&#xff0c;OceanBase 对外正式宣布&#xff1a;将持续践行“一体化”新战略&#xff0c;为关键业务负载打造一体化数据库。同时&#xff0c;会上发布一体化数据库的首个长期支持版本 OceanBase…

html在线生成二维码(附源码)

文章目录 1.设计来源1.1 主界面1.2 美化功能 2.效果和源码2.1 动态效果2.2 源代码 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/134458927 html二维码生成&#xff08;附源码&#xff09;&#xff0c;生成二…

每天一道算法题(四)——移动零(将数组中的零移到最后面)

文章目录 前言1、问题2、示例3、解决方法&#xff08;1&#xff09;方法1&#xff08;2&#xff09;方法2&#xff08;双指针&#xff09; 前言 提示&#xff1a; 1、问题 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的…

如何选择适合企业的ERP管理系统?

如何选择适合企业的ERP管理系统&#xff1f; 企业业务不断发展和扩大&#xff0c;ERP管理系统已成为企业实现信息化管理、提高工作效率、降低成本的重要工具。然而&#xff0c;市场上ERP管理系统种类繁多&#xff0c;如何选择适合自己企业的ERP管理系统成为了企业面临的难题。…

【测试功能篇 01】Jmeter 压测接口最大并发量、吞吐量、TPS

压力测试&#xff0c;我们针对比较关键的接口&#xff0c;可以进行相应的压力测试&#xff0c;主要还是测试看看接口能抗住多少的请求数&#xff0c;TPS稳定在多少&#xff0c;也就是吞吐量多少 安装 Jmeter的安装很简单&#xff0c;官网下载地址 http://jmeter.apache.org/ &…

UE5 - ArchvizExplorer - 数字孪生城市模板 -学习笔记

1、学习资料 https://www.unrealengine.com/marketplace/zh-CN/product/archviz-explorer https://karldetroit.com/archviz-explorer-documentation/ 官网下载的是一个简单版&#xff0c;需要下载扩展&#xff0c;并拷贝到项目录下&#xff0c;才有完整版 https://drive.googl…

AH8691-60V降压至3.3V电源芯片:ESOP8封装解决方案

AH8691-60V降压至3.3V电源芯片&#xff1a;ESOP8封装解决方案 随着电子设备的日益普及&#xff0c;电源管理芯片的重要性也日益凸显。一款高效率、低功耗的电源芯片可以大大提高电子设备的性能和可靠性。今天&#xff0c;我们将介绍一款60V降压至3.3V电源芯片&#xff0c;采用…

websocket详解

一、什么是Websocket WebSocket 是一种在单个 TCP 连接上进行 全双工 通信的协议&#xff0c;它可以让客户端和服务器之间进行实时的双向通信。 WebSocket 使用一个长连接&#xff0c;在客户端和服务器之间保持持久的连接&#xff0c;从而可以实时地发送和接收数据。 在 Web…

工业镜头中远心镜头的特点

远心镜头 在Z轴&#xff08;光轴&#xff09;方向&#xff0c;理论上具有同样成像范围。 消除了透视效应。 消除了渐晕现像。

OpenCV快速入门:像素操作和图像变换

文章目录 前言1. 像素操作1.1 像素统计1.2 两个图像之间的操作1.2.1 图像加法操作1.2.3 图像加权混合 1.3 二值化1.4 LUT&#xff08;查找表&#xff09;1.4.1 查找表原理1.4.2 代码演示 2 图像变换2.1 旋转操作2.1.1 旋转的基本原理2.1.2 代码实现 2.2 缩放操作2.3 平移操作2.…

【字符编码系列一】ASCII编码是什么?

介绍 ASCII 编码于 1967 年第一次发布&#xff0c;最后一次更新是在 1986 年&#xff0c;迄今为止共收录了 128 个字符&#xff0c;包含了基本的拉丁字母&#xff08;英文字母&#xff09;、阿拉伯数字&#xff08;也就是 1234567890&#xff09;、标点符号&#xff08;,.!等&…

直线插补-逐点比较法

直线插补-逐点比较法 逐点比较法四个节拍的工作流程如图所示举例1 逐点比较法 逐点比较法逐点比较法是通过逐点比较刀具与所需插补曲线之间的相对位置&#xff0c;确定刀具的进给方向&#xff0c;进而加工出工件轮廓的插补方法。刀具从加工起点开始&#xff0c;按照“靠近曲线…