【问题标题】:Spring Boot elastic Search Query with constraint具有约束的 Spring Boot 弹性搜索查询
【发布时间】:2021-06-29 13:38:41
【问题描述】:

我对这个弹性搜索和 Spring Boot 世界很陌生,过去 2-3 天我一直在尝试搜索这个解决方案,遗憾的是我无法(可能是因为我是新手)。

我在弹性搜索中有 3 列,第一列是 ID,第二列是名称(我在此基础上创建自动完成 API),第三个字段包含一组称为数字的数字。我的用例是,对于第 3 列中的特定数字,我想要来自第 2 列的自动完成建议。

这是我用这段代码实现的,它可以工作:repo.findByNumbersAndName(String, String)

但这不允许我设置模糊性、通配符查询和其他搜索参数,所以我尝试使用 QueryBuilders 但我在构建逻辑方面没有成功(我基本上尝试使用 BooleanQueryBuilder),所以如果有人可以帮助我,它会真的很有帮助!

Spring Boot 版本 - 2.4.2

提前致谢。

编辑1:-

为了更好地理解我的用例,假设这是我存储在弹性搜索中的内容

Id | Name   | Numbers |
-----------------------
a1 | ashwin | 1       |
a2 | Ram    | 3       |
a3 | Kumar  | 2       |
a4 | Some   | 2       |
a5 | body   | 1       |
a6 | any    | 3       |
a7 | one    | 4       |
a8 | ashwin | 2       |

现在我应该有控制权来指定我的查询,说对于这个数字(比如说 1),如果输入自动完成“a”,自动完成的可能性是什么。然后程序应该只在数字列中搜索数字为“1”的可能性,因此在这种情况下,只有一个输出是“ashwin”。

编辑2:-

我相信我的配置和查询方法和你所做的一样,我只是粘贴我所做的。一个更新是,虽然数据库中的 Number 字段包含 Integers,但它们存储为 String 数据类型,这在 term Query 时会有什么不同吗?

这是我的 elastic-analyzer.json

{

  "analysis": {
    "filter": {
      "autocomplete_filter": {
        "type": "edge_ngram",
        "min_gram": 3,
        "max_gram": 30
      }
    },
    "analyzer": {
      "autocomplete_search": {
        "type": "custom",
        "tokenizer": "standard",
        "filter": [
          "lowercase",
          "stop"
          
        ]
      },
      "autocomplete_index": {
        "type": "custom",
        "tokenizer": "standard",
        "filter": [
          "lowercase",
          "autocomplete_filter",
          "stop"
        ]
      }
    }
  }
}

我正在使用它来生成查询:-

BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
        
        .must(QueryBuilders.termQuery("Number", number))
        .must(QueryBuilders.matchQuery("Name", search_word));

以上以这种格式生成查询-

{
  "bool" : {
    "must" : [
      {
        "term" : {
          "Number" : {
            "value" : "1",
            "boost" : 1.0
          }
        }
      },
      {
        "match" : {
          "Name" : {
            "query" : "ash",
            "operator" : "OR",
            "prefix_length" : 0,
            "max_expansions" : 50,
            "fuzzy_transpositions" : true,
            "lenient" : false,
            "zero_terms_query" : "NONE",
            "auto_generate_synonyms_phrase_query" : true,
            "boost" : 1.0
          }
        }
      }
    ],
    "adjust_pure_negative" : true,
    "boost" : 1.0
  }

这是产生空数组,不明白为什么?我觉得下面的属性相当于你在索引映射中提到的属性

@Id
@Field(type = FieldType.Text)
private String Id;

@Field(type = FieldType.Text, analyzer = "autocomplete_index", searchAnalyzer = "autocomplete_search")
private String Name;

@Field(type = FieldType.Text)
private String Number;

感谢@ESCoder

编辑 3:-

在@ESCoder 的帮助下,我也偶然发现了这一点,

BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
        
        .must(QueryBuilders.matchQuery("Number", search_number).boost(1f).operator(Operator.AND))
        .must(QueryBuilders.matchQuery("Name", keyword).boost(0.4f));

这是为 ElasticSearch 生成的 Query spring,

{
  "bool" : {
    "must" : [
      {
        "match" : {
          "Number" : {
            "query" : "1",
            "operator" : "AND",
            "prefix_length" : 0,
            "max_expansions" : 50,
            "fuzzy_transpositions" : true,
            "lenient" : false,
            "zero_terms_query" : "NONE",
            "auto_generate_synonyms_phrase_query" : true,
            "boost" : 1.0
          }
        }
      },
      {
        "match" : {
          "Name" : {
            "query" : "ash",
            "operator" : "OR",
            "fuzziness" : "1",
            "prefix_length" : 0,
            "max_expansions" : 50,
            "fuzzy_transpositions" : true,
            "lenient" : false,
            "zero_terms_query" : "NONE",
            "auto_generate_synonyms_phrase_query" : true,
            "boost" : 0.4
          }
        }
      }
    ],
    "adjust_pure_negative" : true,
    "boost" : 1.0
  }
}

【问题讨论】:

    标签: java spring spring-boot elasticsearch full-text-search


    【解决方案1】:

    添加一个包含索引数据、映射、搜索查询和搜索结果的工作示例

    索引映射:

    {
      "settings": {
        "analysis": {
          "filter": {
            "autocomplete_filter": {
              "type": "edge_ngram",
              "min_gram": 1,
              "max_gram": 4
            }
          },
          "analyzer": {
            "autocomplete": {
              "type": "custom",
              "tokenizer": "standard",
              "filter": [
                "lowercase",
                "autocomplete_filter"
              ]
            }
          }
        }
      },
      "mappings": {
        "properties": {
          "Name": {
            "type": "text",
            "analyzer": "autocomplete",
            "search_analyzer": "standard"
          },
          "Id": {
            "type": "text"
          },
          "Numbers": {
            "type": "integer"
          }
        }
      }
    }
    

    索引数据:

    {
      "Name": "ashwin",
      "Id": "a1",
      "Numbers": 1
    }
    {
      "Name": "ashwin",
      "Id": "a1",
      "Numbers": 2
    }
    

    搜索查询:

    {
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "Name": "a"
              }
            },
            {
              "term": {
                "Numbers": 1
              }
            }
          ]
        }
      }
    }
    

    搜索结果:

    "hits": [
          {
            "_index": "66923434",
            "_type": "_doc",
            "_id": "1",
            "_score": 1.2630212,
            "_source": {
              "Name": "ashwin",
              "Id": "a1",
              "Numbers": 1
            }
          }
        ]
    

    更新 1:

    使用您当前的索引映射设置,将为ashwin 生成以下标记

    GET /_analyze
    {
      "analyzer" : "autocomplete",
      "text" : "ashwin"
    }
    

    代币是:

    {
      "tokens": [
        {
          "token": "ash",
          "start_offset": 0,
          "end_offset": 6,
          "type": "<ALPHANUM>",
          "position": 0
        },
        {
          "token": "ashw",
          "start_offset": 0,
          "end_offset": 6,
          "type": "<ALPHANUM>",
          "position": 0
        },
        {
          "token": "ashwi",
          "start_offset": 0,
          "end_offset": 6,
          "type": "<ALPHANUM>",
          "position": 0
        },
        {
          "token": "ashwin",
          "start_offset": 0,
          "end_offset": 6,
          "type": "<ALPHANUM>",
          "position": 0
        }
      ]
    }
    

    您需要修改索引映射,而不是"min_gram": 3,您需要将其更改为"min_gram": 1

    更新 2:

    您甚至需要将"search_analyzer" 更改为standard

    【讨论】:

    • 嗨@ESCoder,感谢您的快速回复!我已经更新了我的答案,如果我的代码有任何问题,请告诉我,因为我没有发现我之前实现的内容和你现在发送的内容有任何区别。再次感谢!
    • @ashwinramkumar 请仔细阅读答案的更新部分,如果这能解决您的问题,请告诉我?
    • 如果我的搜索查询是“ash”(3 个字母单词),其中 Number == “1”,即使 ngram=3(意思是“ash”存在)也应该能够找到它作为令牌),但是当我运行结果时我仍然得到一个空列表。谢谢!!
    • @ashwinramkumar 您需要设置"search_analyzer": "standard"。请按照上面的答案所示进行索引映射。现在,当您搜索ash 时,您将获得所需的结果。让我知道这是否适合你:-)
    • 是的..添加了赞成票!再次感谢您的帮助
    猜你喜欢
    • 2018-06-08
    • 2014-11-04
    • 1970-01-01
    • 2020-10-22
    • 2023-04-01
    • 1970-01-01
    • 2019-11-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多