跳到内容

索引参数和全文搜索

在定义混合索引时,可以为添加到索引中的每个属性键选择性地指定一组参数。这些参数控制特定键的索引方式。JanusGraph 识别以下索引参数。是否支持这些参数取决于配置的索引后端。特定的索引后端除了此处列出的参数外,可能还支持自定义参数。

在索引字符串值(即数据类型为 String.class 的属性键)时,可以选择将其索引为文本或字符字符串,这由 mapping 参数类型控制。

当值被索引为文本时,字符串会被分词为词袋,这允许用户有效地查询包含一个或多个词的所有匹配项。这通常被称为全文搜索。当值被索引为字符字符串时,字符串会“原样”索引,无需任何进一步的分析或分词。这有助于查询精确的字符序列匹配。这通常被称为字符串搜索

全文搜索

默认情况下,字符串被索引为文本。为了明确此索引选项,可以在将属性键索引为文本时定义映射。

mgmt = graph.openManagement()
summary = mgmt.makePropertyKey('booksummary').dataType(String.class).make()
mgmt.buildIndex('booksBySummary', Vertex.class).addKey(summary, Mapping.TEXT.asParameter()).buildMixedIndex("search")
mgmt.commit()

这与标准混合索引定义相同,只是额外添加了一个指定索引中映射的参数——在本例中为 Mapping.TEXT

当字符串属性被索引为文本时,字符串值被分词为词袋。精确的分词取决于索引后端及其配置。JanusGraph 的默认分词将字符串按非字母数字字符分割,并删除任何少于 2 个字符的词。索引后端使用的分词可能不同(例如,停用词被删除),这可能导致在事务内部进行的修改和索引后端中已提交数据的全文搜索查询处理方式上存在细微差异。

当字符串属性被索引为文本时,索引后端仅支持图查询中的全文搜索谓词。全文搜索不区分大小写。

  • textContains:如果文本字符串中(至少)有一个词与查询字符串匹配,则为 true
  • textContainsPrefix:如果文本字符串中(至少)有一个词以查询字符串开头,则为 true
  • textContainsRegex:如果文本字符串中(至少)有一个词与给定正则表达式匹配,则为 true
  • textContainsFuzzy:如果文本字符串中(至少)有一个词与查询字符串相似(基于 Levenshtein 编辑距离),则为 true
  • textContainsPhrase:如果文本字符串包含查询字符串中的词序列,则为 true
import static org.janusgraph.core.attribute.Text.*
g.V().has('booksummary', textContains('unicorns'))
g.V().has('booksummary', textContainsPrefix('uni'))
g.V().has('booksummary', textContainsRegex('.*corn.*'))
g.V().has('booksummary', textContainsFuzzy('unicorn'))
g.V().has('booksummary', textContainsPhrase('unicorn horn'))

Elasticsearch 后端扩展了此功能,并支持上述谓词的否定形式以及短语匹配

  • textNotContains:如果文本字符串中没有词与查询字符串匹配,则为 true
  • textNotContainsPrefix:如果文本字符串中没有词以查询字符串开头,则为 true
  • textNotContainsRegex:如果文本字符串中没有词与给定正则表达式匹配,则为 true
  • textNotContainsFuzzy:如果文本字符串中没有词与查询字符串相似(基于 Levenshtein 编辑距离),则为 true
  • textNotContainsPhrase:如果文本字符串不包含查询字符串中的词序列,则为 true

字符串搜索谓词(见下文)可以在查询中使用,但它们需要在内存中进行过滤,这可能非常耗时。

要将字符串属性索引为字符序列,而不进行任何分析或分词,请将映射指定为 Mapping.STRING

mgmt = graph.openManagement()
name = mgmt.makePropertyKey('bookname').dataType(String.class).make()
mgmt.buildIndex('booksBySummary', Vertex.class).addKey(name, Mapping.STRING.asParameter()).buildMixedIndex("search")
mgmt.commit()

配置字符串映射后,字符串值会被索引并可以“原样”查询 - 包括停用词和非字母字符。但是,在这种情况下,查询必须与整个字符串值匹配。因此,字符串映射在索引被视为一个词元的短字符序列时很有用。

当字符串属性被索引为字符串时,索引后端仅支持图查询中的以下谓词。字符串搜索区分大小写。

  • eq:如果字符串与查询字符串相同
  • neq:如果字符串与查询字符串不同
  • textPrefix:如果字符串值以给定查询字符串开头
  • textRegex:如果字符串值完全匹配给定的正则表达式
  • textFuzzy:如果字符串值与给定查询字符串相似(基于 Levenshtein 编辑距离)
import static org.apache.tinkerpop.gremlin.process.traversal.P.*
import static org.janusgraph.core.attribute.Text.*
g.V().has('bookname', eq('unicorns'))
g.V().has('bookname', neq('unicorns'))
g.V().has('bookname', textPrefix('uni'))
g.V().has('bookname', textRegex('.*corn.*'))
g.V().has('bookname', textFuzzy('unicorn'))

Elasticsearch 后端扩展了此功能,并支持上述文本谓词的否定形式

  • textNotPrefix:如果字符串值不以给定查询字符串开头
  • textNotRegex:如果字符串值不完全匹配给定的正则表达式
  • textNotFuzzy:如果字符串值与给定查询字符串不相似(基于 Levenshtein 编辑距离)

全文搜索谓词可以在查询中使用,但它们需要在内存中进行过滤,这可能非常耗时。

如果您使用 Elasticsearch,可以将属性同时索引为文本和字符串,从而允许您使用所有谓词进行精确和模糊匹配。

mgmt = graph.openManagement()
summary = mgmt.makePropertyKey('booksummary').dataType(String.class).make()
mgmt.buildIndex('booksBySummary', Vertex.class).addKey(summary, Mapping.TEXTSTRING.asParameter()).buildMixedIndex("search")
mgmt.commit()

请注意,数据将在索引中存储两次,一次用于精确匹配,一次用于模糊匹配。

TinkerPop 文本谓词

也可以将 TinkerPop 文本谓词与 JanusGraph 一起使用,但这些谓词不使用索引,这意味着它们需要在内存中进行过滤,这可能非常耗时。

import static org.apache.tinkerpop.gremlin.process.traversal.TextP.*;
g.V().has('bookname', startingWith('uni'))
g.V().has('bookname', endingWith('corn'))
g.V().has('bookname', containing('nico'))

地理映射

默认情况下,JanusGraph 支持索引点类型的地理属性,并通过圆形或框查询地理属性。要索引支持通过任何地理形状类型查询的非点地理属性,请将映射指定为 Mapping.BKD(ElasticSearch 首选)或 Mapping.PREFIX_TREE(Solr、Lucene 和 ElasticSearch 6 支持。ElasticSearch 7 中已弃用。ElasticSearch 8 中已删除支持)

mgmt = graph.openManagement()
name = mgmt.makePropertyKey('border').dataType(Geoshape.class).make()
mgmt.buildIndex('borderIndex', Vertex.class).addKey(name, Mapping.BKD.asParameter()).buildMixedIndex("search")
mgmt.commit()

当使用 Mapping.PREFIX_TREE 时,可以指定额外的参数来调整底层前缀树映射的配置。这些可选参数包括前缀树中使用的层数以及相关的精度。

mgmt = graph.openManagement()
name = mgmt.makePropertyKey('border').dataType(Geoshape.class).make()
mgmt.buildIndex('borderIndex', Vertex.class).addKey(name, Mapping.PREFIX_TREE.asParameter(), Parameter.of("index-geo-max-levels", 18), Parameter.of("index-geo-dist-error-pct", 0.0125)).buildMixedIndex("search")
mgmt.commit()

请注意,某些索引后端(例如 Solr)可能需要额外的外部模式配置才能支持和调整非点属性的索引。

信息

Mapping.BKD 映射是 ElasticSearch 首选,但它不支持圆形形状。Instead of indexing a Circle as it was with Mapping.PREFIX_TREE there are Circle processors available which transform Circle into other shapes and index those shapes instead.根据所使用的精度配置,对这些圆的搜索可能会有所不同。精度越高,索引期间使用的点越多,这可能会影响存储大小和索引时间。有关 BKD 圆形处理器的更多信息,请参阅 index.[X].bkd-circle-processor 配置属性。