Kibana 控制台中提供语义、向量和混合搜索

作者:来自 Elastic Mark_Laney

想要将常规 Elasticsearch 查询与新的 AI 搜索功能结合起来吗?那么,你不需要连接到某个第三方的大型语言模型(LLM)吗?不。你可以使用 Elastic 的 ELSER 模型来改进现有搜索,以创建语义向量,并将其与常规搜索相结合,以获得更相关的搜索结果!

介绍

当谈到使用 AI 并将向量搜索应用于 Elastic 上的数据时,我看到很多教程和文章,它们可能变得相当复杂。我想表明,你可以利用今天正在运行的现有搜索,并通过语义和向量搜索来增强它们。你无需连接任何外部 LLM 或付费给任何大公司来处理你的数据。仅在 Elasticsearch 和 Kibana 中,你就可以下载 Elastic 的语义模型 ELSER,处理你的数据以添加描述向量,并增强你的搜索以探索改进。你不需要 LangChain、Python、chatGPT 或任何其他外部工具。

:目前 ELSER 只提供对英文的支持。它是一种稀疏向量的搜索方式。更多阅读,请参阅 “Elasticsearch:使用 ELSER 释放语义搜索的力量:Elastic Learned Sparse EncoderR”。

平台

我们将运行的搜索是在 Elasticsearch 和 Kibana 8.13.4 版本上完成的。你可以在任何你喜欢的平台上运行它们,无论是在本地还是在云端。

数据

我们将搜索的数据来自 Kaggle 的一组称为 “recipes” 的开放许可数据集。原始数据集可以从这里下载(在《使用 Elastic 的从业者向量搜索》第 173 页中讨论)。我下载了该文件并将其命名为 “allrecipes.csv”。

或者你可以从我的 GitHub 下载数据集。请打开该链接以在后续说明中下载其他文件。

删除重复数据

原始数据集中存在重复的条目。我编写了一个小型 Python 脚本来对它们进行重复数据删除。该脚本位于 GitHub 项目文件夹中,名为 dedupecsv.py。去重的结果文件叫做 allrecipes_dedupe.csv,它也在项目文件中。如果要自己运行 dedupecsv.py,则需要安装 python 库 pandas。 (例如 pip install pandas)。但是你不必执行这个重复数据删除,因为它已经完成,结果是 allrecipes_dedupe.csv。下载该文件。

索引数据

我能够使用 Filebeat 和(甚至更简单的)Kibana 中的文件上传器将数据导入 Elasticsearch 中的索引,最近使用的是 8.13.4 版本,但旧版本也可以使用。如果你使用 Filebeat 将 allrecipes_dedupe.csv 导入 Elasticsearch,则配置文件为 filebeat.yml ,并且副本位于项目文件夹中。我按照 “快速安装” 文档安装并使用 filebeat 作为 “自托管” 系统。如果你正在使用远程系统(如 Cloud 或 Strigo),请将 filebeat.yml 和 allrecipes_dedupe.csv 都 scp 到你的实例。

但使用文件上传器更容易,只需下载 allrecipes_dedupe.csv 并将其拖放到 Kibana 中。

使用任一方法,创建一个名为 “recipes” 的 Elasticsearch 索引。 Filebeat 将为你完成此操作。你在文件上传器中输入该名称。

Kibana

步骤 1:让我们验证食谱索引是否已成功导入 Elasticsearch。

在 Kibana 控制台(Kibana 主菜单 -> Management -> Dev Tools)中运行此命令:

GET _cat/indices?v&s=index

_cat API 提供行和列的输出。问号 (?v&s=index) 后面的字符是显示标题标签 (v) 和按 “index” 列排序 (&s=index) 的选项。

验证 recipes 索引的另一种方法是使用 _count API。

GET recipes/_count

步骤 2:下载 ELSER

Kibana UI 让我们可以在机器学习区域下载模型。转到主菜单-> Machine Learning。找到并点击 “Trained Models”。你应该会看到一个可用模型的简短列表。对于非英特尔环境,请下载 .elser_model_2。如果你的平台使用的是Intel x86 芯片,请下载专门准备的.elser_model_2_linux-x86_64。

步骤 3:启动模型

开始部署该模型进行推理。使用一个分配和四个线程。大多数情况下,分配会消耗一个核心,而线程就是该核心上的线程。下面的 API 调用为模型提供了一个名称 “elser_model”。

如果你运行的是 Intel x86 芯片:

POST _ml/trained_models/.elser_model_2_linux-x86_64/deployment/_start?deployment_id=elser_model&number_of_allocations=1&threads_per_allocation=4

否则:

POST _ml/trained_models/.elser_model_2/deployment/_start?deployment_id=elser_model&number_of_allocations=1&threads_per_allocation=4

如果需要启动和停止模型,可以执行以下操作:

POST _ml/trained_models/elser_model/deployment/_stop

如果管道正在调用模型(我们稍后会讲到):

POST _ml/trained_models/elser_model/deployment/_stop?force=true

确保模型处于启动状态:

GET _ml/trained_models/_stats/
GET _ml/trained_models/_stats?filter_path=trained_model_stats.deployment_stats.state

步骤 4:浏览食谱索引

运行这些命令来检查 recipes 索引的内容和属性。

检查索引中的某些文档:

GET recipes/_search

要查看字段及其数据类型:

GET recipes/_mapping

要查看索引的所有属性(映射、设置、别名),实际上更容易:

GET recipes

步骤 5:改进映射

如果我们运行这个:

GET recipes/_search?filter_path=hits.hits._source.id

请注意,所有 ID 都是小整数。然而,如果我们回过头来检查映射,我们会发现 ID 的数据类型可能是文本/关键字或长整型(取决于我们用来索引配方的工具)。

还要注意,summary 字段是数据类型 text,默认使用标准分析器。如果有英语分析器结果(提供词干结果),这将对我们的搜索很有用。这样,如果我们搜索“stewed” 西红柿的 summary,结果就会是 stewed、stew、stews、stewing等,这可能有助于更轻松地获得相关食谱。

此外,我们还需要创建一个字段来保存数据向量化的结果。稍后我们将配置一个摄取节点管道处理器来指示模型将结果写入名为 ml.tokens 的字段。正如这里所解释的,ELSER 模型结果应该存储为我们的向量嵌入的数据类型 “稀疏向量”。

考虑到这些改变,让我们创建一个具有所有改进的映射属性的不存在的索引。

PUT recipes_embeddings
{
  "mappings": {
    "properties": {
      "id": {
        "type": "short"
      },
      "group": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "ingredient": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "n_rater": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "n_reviewer": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "name": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "process": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "rating": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "summary": {
        "type": "text",
        "analyzer": "english",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "ml.tokens": {
        "type": "sparse_vector"
      }
    }
  }
}

步骤 6:其他文档修复

让我们再次检查一些有关食谱的文件。

GET recipes/_search
{
  "size": 2000,
  "_source": ["ingredient"]
}

如果你在控制台的右侧按 cntr+f find,你可能会注意到有些文档带有双引号或三引号。

在这里,我们创建一个摄取节点管道,将三重引号替换为单引号。
我们将我们的管道称为 “doublequotes”。

PUT _ingest/pipeline/doublequotes
{
  "processors": [
    {
      "gsub": {
        "field": "ingredient",
        "pattern": "\"(.*?)",
        "replacement": ""
      }
    }
  ]
}

为了测试我们的管道,我们可以使用_simulate API。

POST _ingest/pipeline/doublequotes/_simulate
{
  "docs": [
    {
      "_index": "recipes",
      "_id": "id",
      "_source": {
        "ingredient": """shredded cheese, and even some cilantro for a great-tasting breakfast burrito that will keep your appetite curbed all day long.","prep: 15 mins,cook: 5 mins,total: 20 mins,Servings: 2,Yield: 2 burritos","2 (10 inch) flour tortillas + 1 tablespoon butter + 4 medium eggs + 1 cup shredded mild Cheddar cheese + 1 Hass avocado - peeled, pitted, and sliced + 1 small tomato, chopped + 1 small bunch fresh cilantro, chopped, or to taste (Optional) + 1 pinch salt and ground black pepper to taste + 1 dash hot sauce, or to taste (Optional)""",
        "tags": 2342
      }
    }
  ]
}

步骤 7:带推理的管道

下面我们创建一个管道来清理引文并应用推理处理器。推理处理器是我们用来针对索引中的成分字段运行我们的模型(在本例中为 ELSER)的工具。回想一下,我们部署的名称是 else_model,我们在这里看到它被称为 model_id。我们将此管道称为 else_clean_recipes。

PUT _ingest/pipeline/elser_clean_recipes
{
  "processors": [
    {
      "pipeline": {
        "name": "doublequotes"
      },
      "inference": {
        "model_id": "elser_model",
        "target_field": "ml",
        "field_map": {
          "ingredient": "text_field"
        },
        "inference_config": {
          "text_expansion": {
            "results_field": "tokens"
          }
        }
      }
    }
  ]
}

请注意,模型默认对 “text_field” 字段进行向量化。在“field_map”行中,我们配置推理处理器以使用不同的字段(在本例中为成分)。

一定要测试。

POST _ingest/pipeline/elser_clean_recipes/_simulate
{
  "docs": [
    {
      "_index": "recipes",
      "_id": "id",
      "_source": {
        "ingredient": """prep: 20 mins,cook: 20 mins,total: 40 mins,Servings: 4,Yield: 4 servings","½ small onion, chopped + ½ tomato, chopped + 1 jalapeno pepper, seeded and minced + 1 sprig fresh cilantro, chopped + 6 eggs, beaten + 4 (10 inch) flour tortillas + 2 cups shredded Cheddar cheese + ¼ cup sour cream, for topping + ¼ cup guacamole, for topping""",
        "tags": 2342
      }
    },
     {
      "_index": "recipes",
      "_id": "id",
      "_source": {
        "ingredient":
    """"shredded cheese, and even some cilantro for a great-tasting breakfast burrito that will keep your appetite curbed all day long.","prep: 15 mins,cook: 5 mins,total: 20 mins,Servings: 2,Yield: 2 burritos","2 (10 inch) flour tortillas + 1 tablespoon butter + 4 medium eggs + 1 cup shredded mild Cheddar cheese + 1 Hass avocado - peeled, pitted, and sliced + 1 small tomato, chopped + 1 small bunch fresh cilantro, chopped, or to taste (Optional) + 1 pinch salt and ground black pepper to taste + 1 dash hot sauce, or to taste (Optional)"""
      }},
      {"_index": "recipes",
      "_id": "id",
      "_source": {  
        "ingredient": """shredded cheese, and even some cilantro for a great-tasting breakfast burrito that will keep your appetite curbed all day long.","prep: 15 mins,cook: 5 mins,total: 20 mins,Servings: 2,Yield: 2 burritos","2 (10 inch) flour tortillas + 1 tablespoon butter + 4 medium eggs + 1 cup shredded mild Cheddar cheese + 1 Hass avocado - peeled, pitted, and sliced + 1 small tomato, chopped + 1 small bunch fresh cilantro, chopped, or to taste (Optional) + 1 pinch salt and ground black pepper to taste + 1 dash hot sauce, or to taste (Optional)"""}}
  ]
}

步骤 8:通过管道处理数据

现在我们有了管道,是时候处理我们的索引了。我们将使用 _reindex API 将数据从 recipes 索引发送到 recipes_embeddings。在此过程中,数据将通过我们的管道来创建嵌入。

重新索引可能需要很长时间,因此我们在这里使用一个名为 wait_for_completion=false 的选项进行运行。

当我们运行命令时,它将生成一个 ID 号,我们可以使用它来检查进度。确保将此 ID 复制并粘贴到某处。

此外,重新索引正在使用选项......

requests_per_second=-1&timeout=60m

...分别以尽可能快的速度运行并且不会太快超时。

警告:可能需要大约 15-30 分钟

POST _reindex?wait_for_completion=false&requests_per_second=-1&timeout=60m
{
  "conflicts": "proceed", 
  "source": {
    "index": "recipes",
    "size": 500
  },
  "dest": {
    "index": "recipes_embeddings",
    "pipeline": "elser_clean_recipes"
  }
}

复制并使用任务编号来跟踪重新索引过程。

GET _tasks/< paste task number here >

例如,我复制并粘贴了这个ID:LAV3l8oZTmaR9p8VUVqO3g:373447

如果需要,你可以像这样删除 recipes_embeddings 索引。

DELETE recipes_embeddings

步骤 9:检查已处理的文件

至少一批文档完成后,检查结果。

GET _cat/indices?v&s=i

GET recipes_embeddings/_search

冗长的 ml.tokens 字段使得输出看起来不太好看。你可以像这样抑制它。

GET recipes_embeddings/_search
{ "_source": { "excludes": "ml"} }
GET recipes_embeddings/_count
4808 documents

我们可以运行这个聚合来找到我们可以查询的 “group” 中的所有不同值。

GET recipes_embeddings/_search?size=0
{
  "aggs": {
    "all the groups": {
      "terms": {
        "field": "group.keyword",
        "size": 200
      }
    }
  }
}

有多少个桶?

GET recipes_embeddings/_search
{
  "size": 0, 
  "aggs": {
    "how many buckets": {
      "cardinality": {
        "field": "group.keyword",
        "precision_threshold": 200
      }
    }
  }
}

我得到了 174 个不同的组。

为了隔离输出中的组以便我们可以在文档中看到它们,你可以运行以下命令:

GET recipes_embeddings/_search?size=1000&_source=group

搜索

最后,数据准备好了,我们可以在 recipes_embeddings 索引上执行搜索。让我们比较一下没有 ELSER 的运行结果和有 ELSER 的运行结果。

搜索 1:Old fashion(老式鸡尾酒)

首先,我们来寻找一种名为 Old Fashion 的鸡尾酒的配方。下面介绍如何进行此操作。

-- 老式波本鸡尾酒 --
1. 将一到两颗樱桃放入老式老式玻璃杯中,并用捣碎器轻轻捣碎。
2. 取橙皮并擦拭玻璃杯边缘内侧,然后将果皮放在樱桃上。
3. 加入冰块、黑麦威士忌、糖和苦味酒。
4. 搅拌均匀即可食用。

首先,没有 ELSER 的情况下:

GET recipes_embeddings/_search
{
  "_source": {
    "excludes": "ml", "includes": ["name","group","summary","ingredient"]},
  "query": {
    "bool": {
      "should": [ { "wildcard": { "group": {"value": "drinks*" }}},
        {
          "multi_match": {
            "type": "phrase", 
            "query": "old fashion",
            "fields": [
              "summary",
              "name"]}},
        {
          "match": {
            "summary": "delicious sensational"
          }
        }
      ]
    }
  }
}

在你的控制台中运行它,你将看到热门点击中有一些非常糟糕的结果。
对我来说,它们都不是饮料(尽管我们搜索了饮料*组)。
我的许多搜索结果中都有诸如 “good old fashion meals and dishes...” 这样的短语,但这并不是我们想要的。

现在让我们用 ELSER 搜索...并看看出色的结果!

GET recipes_embeddings/_search
{
  "_source": {
    "excludes": "ml",
    "includes": [
      "name",
      "group",
      "summary",
      "ingredient"
    ]
  },
  "sub_searches": [
    {
      "query": {
        "bool": {
          "should": [
            {
              "wildcard": {
                "group": {
                  "value": "drinks*"
                }
              }
            },
            {
              "multi_match": {
                "query": "old fashioned",
                "type": "phrase",
                "fields": [
                  "summary",
                  "name"
                ]
              }
            }
          ]
        }
      }
    },
    {
      "query": {
        "text_expansion": {
          "ml.tokens": {
            "model_id": "elser_model",
            "model_text": "old fashioned bourbon whiskey whisky drink"
          }
        }
      }
    }
  ],
  "rank": {
    "rrf": {
      "window_size": 500,
      "rank_constant": 60
    }
  }
}

请注意,所有这些都是成人饮料,并且有几种饮料的名称以 “Old Fashion” 开头。

搜索 2:Shrimp dishes

没有 ELSER:

GET recipes_embeddings/_search
{
  "_source": {
    "excludes": "ml"
  },
  "query": {
    "bool": {
      "should": [
        {
          "wildcard": {
            "group": {
              "value": "main*"
            }
          }
        },
        {
          "multi_match": {
            "type": "phrase", 
            "query": "tempura shrimp",
            "fields": [
              "ingredient",
              "name^2"
            ]
          }
        },
        {
          "match": {
            "summary": "tasty delightful"
          }
        }
      ]
    }
  }
}

前五名的结果相当糟糕:我得到了像 pork tenderloin、Spanish sauce、carrot salad 这样的食谱……甚至没有虾。

使用 ELSER:

GET recipes_embeddings/_search
{
  "_source": {
    "excludes": "ml"
  },
  "sub_searches": [
    {
      "query": {
        "bool": {
          "should": [
            {
              "wildcard": {
                "group": {
                  "value": "main*"
                }
              }
            },
            {
              "multi_match": {
                "query": "tempura shrimp",
                "type":"phrase",
                "fields": [
                  "ingredient",
                  "name^2"
                ]
              }
            }/*,
            {
              "match": {
                "summary": "tasty delightful"
              }
            }*/
          ]
        }
      }
    },
    {
      "query": {
        "text_expansion": {
          "ml.tokens": {
            "model_id": "elser_model",
            "model_text": "tempura shrimp"
          }
        }
      }
    }
  ],
  "rank": {
    "rrf": {
      "window_size": 500,
      "rank_constant": 60
    }
  }
}

排名前五的菜品要好得多:Shrimp with Pasta、Shrimp Scampis、Penne with Shrimp、Penne with Shrimp、Shrimp Quiche

请注意,Elasticsearch 如何通过语义搜索发现 shrimp 和 scampi 以及 prawns 等其他术语也具有相关性。

搜索 3:Spaghetti dishes

没有 ELSER:

GET recipes_embeddings/_search
{
  "_source": {
    "excludes": "ml"
  },
  "query": {
    "bool": {
      "should": [
        {
          "wildcard": {
            "group": {
              "value": "main*"
            }
          }
        },
        {
          "multi_match": {
            "type": "phrase", 
            "query": "Spaghetti Bolognese",
            "fields": [
              "ingredient",
              "name^2"
            ]
          }
        },
        {
          "match": {
            "summary": "tasty delightful"
          }
        }
      ]
    }
  }
}

前五名中又有糟糕的:pork tenderloin, Med. sauce, carrot salad, lime chicken……

我根本不喜欢意大利面。

使用 ELSER:

GET recipes_embeddings/_search?filter_path=hits.hits._source
{
  "_source": {
    "excludes": "ml"
  },
  "sub_searches": [
    {
      "query": {
        "bool": {
          "should": [
            {
              "wildcard": {
                "group": {
                  "value": "main*"
                }
              }
            },
            {
              "multi_match": {
                "query": "Spaghetti Bolognese",
                "type":"phrase",
                "fields": [
                  "ingredient",
                  "name^2"
                ]
              }
            }/*,
            {
              "match": {
                "summary": "tasty delightful"
              }
            }*/
          ]
        }
      }
    },
    {
      "query": {
        "text_expansion": {
          "ml.tokens": {
            "model_id": "elser_model",
            "model_text": "main Spaghetti Bolognese"
          }
        }
      }
    }
  ],
  "rank": {
    "rrf": {
      "window_size": 500,
      "rank_constant": 60
    }
  }
}

改进了很多。很多食材都有意大利面或通心粉

再次排在最前面:Pennes, pastas, spaghettis。

搜索 4:巧克力

没有 ELSER:

GET recipes_embeddings/_search
{
  "_source": {"excludes": "ml"},
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "name": "dessert"
          }
        },
        {
          "match": {
            "ingredient": "chocolate"
          }
        },
        {
          "match": {
            "summary": "tasty delightful"
          }
        }
      ]
    }
  }
}

奶昔和薄饼……?

我找不到任何含巧克力的配料。

使用 ELSER:

GET recipes_embeddings/_search
{
  "_source": {"excludes": "ml"}, 
  "sub_searches": [
    {
      "query": {
        "bool": {
          "should": [
             {
              "match": {
                "name": "dessert"
              }
            },
            {
              "match": {
                "ingredient": "chocolate"
              }
            },
            {
              "match": {
                "summary": "tasty delightful"
              }
            }
          ]
        }
      }
    },
    {
      "query": {
        "text_expansion": {
          "ml.tokens": {
            "model_id": "elser_model",
            "model_text": "dessert chocolate"
          }
        }
      }
    }
  ],
  "rank": {
    "rrf": {
      "window_size": 50,
      "rank_constant": 20
    }
  }
}

Peppermint bark 是巧克力的一个晦涩术语。

Nanaimo bars 是一种巧克力顶上的饼干。我还看到hot chocolate, chocolate muffins, chocolate cake, Oreo truffles 和 cake balls,其中的配料包括巧克力。

我看到很多配料都含有巧克力。

我们再看一下我们可以查询的 “groups”。

GET recipes_embeddings/_search?size=0
{
  "aggs": {
    "all the groups": {
      "terms": {
        "field": "group.keyword",
        "size": 200
      }
    }
  }
}

everyday-cooking 有多少种菜谱?

GET recipes_embeddings/_count
{
  "query": {
    "wildcard": {
      "group.keyword": {
        "value": "everyday-cooking*"
      }
    }
  }
}

我得到 310。

鱼肉三明治 - Fish Sandwich

让我们在日常烹饪中寻找 “Fish Sandwich”。

没有 ELSER:

GET recipes_embeddings/_search
{
  "_source": {
    "excludes": "ml"
  },
  "query": {
    "bool": {
      "should": [
        {
          "wildcard": {
            "group": {
              "value": "everyday-cooking*"
            }
          }
        },
        {
          "multi_match": {
            "type": "phrase", 
            "query": "fish sandwich",
            "fields": [
              "ingredient",
              "name^2"
            ]
          }
        }
      ]
    }
  }
}

没有!

哇,根本没有鱼肉三明治……?

使用 ELSER 添加嵌入搜索。

GET recipes_embeddings/_search
{
  "_source": {
    "excludes": "ml"
  },
  "sub_searches": [
    {
      "query": {
        "bool": {
          "should": [
            {
              "wildcard": {
                "group": {
                  "value": "everyday-cooking*"
                }
              }
            },
            {
              "multi_match": {
                "query": "fish sandwich",
                "type":"phrase",
                "fields": [
                  "ingredient",
                  "name^2"
                ]
              }
            }
          ]
        }
      }
    },
    {
      "query": {
        "text_expansion": {
          "ml.tokens": {
            "model_id": "elser_model",
            "model_text": "fish sandwich"
          }
        }
      }
    }
  ],
  "rank": {
    "rrf": {
      "window_size": 500,
      "rank_constant": 60
    }
  }
}

在右侧搜索 “三明治”。

我看到 tuna patties, tuna salads - 很多鱼,很多都是三明治。

让我们看看“主菜”类别中有多少食谱?

让我们检查一下 “Main” 类别中有多少个食谱?

GET recipes_embeddings/_search
{
  "_source": {
    "excludes": "ml"
  },
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "group": "main*"
          }
        }
      ]
    }
  }
}

我得到了458。

里脊牛排 - Tenderloin Steak

请注意,在美国我们说 “tenderloins or tenderloin steaks”,但在法国它被称为 Chateaubriand。还请注意,“Chateaubriand” 不在任何食谱中。可以使用 multi_match 命令来搜索许多字段,如下所示:

GET recipes_embeddings/_search
{
  "query": {
    "multi_match": {
      "query": "Chateaubriand",
      "fields": ["ingredient","summary","name"]
    }
  }
}

零结果

不使用 ELSER:

GET recipes_embeddings/_search
{
  "_source": {
    "excludes": "ml", "includes": ["name","group","summary","ingredient"]},
  "query": {
    "bool": {
      "should": [ { "wildcard": { "group": {"value": "main*" }}},
        {
          "multi_match": {
            //"type": "phrase", 
            "query": "tenderloin steak Chateaubriand beef",
            "fields": [
              "ingredient",
              "name^2"
            ]
          }
        },
        {
          "match": {
            "summary": "delicious Chateaubriand"
          }
        },
        {
          "match": {
            "ingredient": "beef"
          }
        }
      ]
    }
  }
}

前十名的成绩相当糟糕。Salt and pepper fries, salt bread, Pork Tenderloin 等等。

使用 ELSER:

GET recipes_embeddings/_search
{
  "_source": {
    "excludes": "ml", "includes": ["name","group","summary","ingredient"]},
    "sub_searches": [
      {
        "query": {
          "bool": {
            "should": [
              {
                "wildcard": {"group": {"value": "main*"}}},
              {
                "multi_match": {
                  "query": "tenderloin steak Chateaubriand beef",
                  //"type":"phrase",
                  "fields": [
                    "ingredient",
                    "name^2"
                    ]
                }
              },
              {"match":{
                "ingredient":{
                  "query": "beef"
                }
              }}
              ]
          }
        }
      },
      {
        "query": {
          "text_expansion": {
            "ml.tokens": {
              "model_id": "elser_model",
              "model_text": "tenderloin steak Chateaubriand beef"
            }
          }
        }
      }
      ],
      "rank": {
        "rrf": {
          "window_size": 500,
          "rank_constant": 60
        }
      }
}

更多实际牛排。

恭喜!我们已经研究了许多示例,其中使用 ELSER 对数据进行向量化使我们能够进行语义搜索。我们将常规的、可能预先存在的术语搜索与向量搜索相结合,发现混合搜索结果通常比仅搜索术语本身更相关。

原文:Dec 13th, 2024: [EN] Semantic, Vector, and Hybrid Search all in Kibana Console - Advent Calendar - Discuss the Elastic Stack

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

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

相关文章

Golang Gin系列-3:Gin Framework的项目结构

在Gin教程的第3篇&#xff0c;我们将讨论如何设置你的项目。这不仅仅是把文件扔得到处都是&#xff0c;而是要对所有东西的位置做出明智的选择。相信我&#xff0c;这些东西很重要。如果你做得对&#xff0c;你的项目会更容易处理。当你以后不再为了找东西或添加新功能而绞尽脑…

程序设计:排版、检验报告的上下标解决几种办法

【啰嗦两句】 本文重点在于提供几个针对排版文档、各种检验报告系统等程序设计时&#xff0c;遇到的上下标录入、绘制展示等问题的应对办法&#xff0c;但是准确地说&#xff0c;并没有非常优秀的方案。 【上下标难题】 一般的行业或许对上下标并没有严格要求&#xff0c;多数…

TCP 重传演进:TCP RACK Timer 能替代 RTO 吗

本文的建议适用于想改变 TCP 行为的新协议设计&#xff0c;还是那句话&#xff0c;不要抄 TCP 做 yet another TCP。 RTO 一直是 TCP 传输过程所要尽量避免的&#xff0c;因为它会将状态带入 Loss 进而 Go-Back-N&#xff0c;这是一个昂贵的操作。But 在 Fast-Retransmit 被引…

PCL 新增自定义点类型【2025最新版】

目录 一、自定义点类型1、前言2、定义方法3、代码示例二、合并现有类型三、点云按时间渲染1、CloudCompare渲染2、PCL渲染博客长期更新,本文最近更新时间为:2025年1月18日。 一、自定义点类型 1、前言 PCL库自身定义了很多点云类型,但是在使用的时候时如果要使用自己定义的…

Python操作Excel——openpyxl使用笔记(5)

5 其他操作 5.1 合并单元格 有些Excel表格存在合并多个单元格的情况&#xff0c;此时可以使用工作表的merge_cells函数&#xff0c;例如合并第1~2行和1~2列&#xff1a; import openpyxl from openpyxl.comments import Comment wb openpyxl.load_workbook(./test.xlsx) w…

Linux简介和环境搭建

Linux 介绍和环境搭建 1、发行版本 Linux 操作系统有多个主流发行版本&#xff0c;每个版本根据不同的目标、特点和使用场景为用户提供了不同的功能和体验。 Ubuntu • 特点&#xff1a;Ubuntu 是最为人熟知的 Linux 发行版之一&#xff0c;强调易用性和用户友好性&#xff…

LabVIEW时域近场天线测试

随着通信技术的飞速发展&#xff0c;特别是在5G及未来通信技术中&#xff0c;天线性能的测试需求日益增加。对于短脉冲天线和宽带天线的时域特性测试&#xff0c;传统的频域测试方法已无法满足其需求。时域测试方法在这些应用中具有明显优势&#xff0c;可以提供更快速和精准的…

SQL Server查询计划操作符——查询计划相关操作符(4)

7.3. 查询计划相关操作符 28)Declare:该操作符在查询计划中分配一个本地变量。该操作符是一个语言元素。该操作符具体如图7.2-28所示。 图 7.2-28 查询计划操作符Declare示例 29)Delete:该操作符从一个对象中删除满足其参数列中可选谓词的数据行。该操作符具体如图7.2-29…

复用类(3):在组合与继承之间选择、protected关键字、向上转型

1 在组合与继承之间选择 组合和继承都允许在新的类中放置子对象&#xff0c;组合是显式地这样做&#xff0c;而继承则是隐式地做。你或许想知道二者之间的区别何在&#xff0c;以及怎样在二者之间做出选择。 组合技术通常用于想在新类中使用现有类的功能而非它的接口这种情形。…

Java-数据结构-二叉树习题(1)

对于二叉树的学习&#xff0c;主要的还是得多多练习~毕竟二叉树属于新的知识&#xff0c;并且也并不是线性结构&#xff0c;再加上经常使用递归的方法解决二叉树的问题&#xff0c;所以代码的具体流程还是无法看到的&#xff0c;只能通过画图想象&#xff0c;所以还是必须多加练…

彩色图像面积计算一般方法及MATLAB实现

一、引言 在数字图像处理中&#xff0c;经常需要获取感兴趣区域的面积属性&#xff0c;下面给出图像处理的一般步骤。 1.读入的彩色图像 2.将彩色图像转化为灰度图像 3.灰度图像转化为二值图像 4.区域标记 5.对每个区域的面积进行计算和显示 二、程序代码 %面积计算 cle…

计算机网络 (41)文件传送协议

前言 一、文件传送协议&#xff08;FTP&#xff09; 概述&#xff1a; FTP&#xff08;File Transfer Protocol&#xff09;是互联网上使用得最广泛的文件传送协议。FTP提供交互式的访问&#xff0c;允许客户指明文件的类型与格式&#xff08;如指明是否使用ASCII码&#xff0…

vscode的安装与使用

下载 地址&#xff1a;https://code.visualstudio.com/ 安装 修改安装路径&#xff08;不要有中文&#xff09; 点击下一步&#xff0c;创建桌面快捷方式&#xff0c;等待安装 安装中文插件 可以根据自己的需要安装python和Jupyter插件

用Cursor生成一个企业官网前端页面(生成腾讯、阿里官网静态页面)

用Cursor生成一个企业官网前端页面 第一版&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><…

简要认识Web技术三剑客:HTMLCSSJavaScript

目录 一、web标准二、什么是HTML三、什么是CSS四、什么是JavaScript 黑马JAVAWeb飞书在线讲义地址&#xff1a; https://heuqqdmbyk.feishu.cn/wiki/LYVswfK4eigRIhkW0pvcqgH9nWd 一、web标准 Web标准也称网页标准&#xff0c;由一系列的标准组成&#xff0c;大部分由W3C&…

python(25) : 含有大模型生成的公式的文本渲染成图片并生成word文档(支持flask接口调用)

公式样例 渲染前 \[ \sqrt{1904.615384} \approx 43.64 \] 渲染后 安装依赖 pip install matplotlib -i https://mirrors.aliyun.com/pypi/simple/ requestspip install sympy -i https://mirrors.aliyun.com/pypi/simple/ requestspip install python-docx -i https…

2024CVPR《HomoFormer》

这篇论文提出了一种名为HomoFormer的新型Transformer模型,用于图像阴影去除。论文的主要贡献和创新点如下: 1. 研究背景与动机 阴影去除的挑战:阴影在自然场景图像中普遍存在,影响图像质量并限制后续计算机视觉任务的性能。阴影的空间分布不均匀且模式多样,导致传统的卷积…

PE文件:节表-添加节

在所有节的空白区域都不够存放我们想要添加的数据时&#xff0c;这个时候可以通过添加节来扩展我们可操作的空间去存储新的数据&#xff08;如导入表、代码或资源&#xff09;。 过程步骤 1.判断是否有足够的空间添加节表 PE文件的节表紧跟在PE头之后&#xff0c;每个节表的…

窥探QCC518x/308x系列与手机之间的蓝牙HCI记录与分析 - 手机篇

今天要介绍给大家的是, 当我们在开发高通耳机时如果遇到与手机之间相容性问题, 通常会用Frontline或Ellisys的Bluetooth Analyzer来截取资料分析, 如果手边没有这样的仪器, 要如何窥探Bluetooth的HCI log.这次介绍的是手机篇. 这次跟QCC518x/QCC308x测试的手机是Samsung S23 U…

【MySQL】数据库约束和多表查询

目录 1.前言 2.数据库约束 2.1约束类型 2.2?NULL约束 2.3 NUIQUE&#xff1a;唯一约束 2.4?DEFAULT&#xff1a;默认值约束 2.5?PRIMARY KEY&#xff1a;主键约束 2.6 FOREIGN KEY&#xff1a;外键约束 1.7?CHECK约束 3.表的设计? 3.1一对一 3.2一对多 3.3多…