|
161 | 161 | },
|
162 | 162 | {
|
163 | 163 | "cell_type": "code",
|
164 |
| - "execution_count": 1, |
| 164 | + "execution_count": 3, |
165 | 165 | "id": "67ab8afa-f7c6-4fbf-b596-cb512da949da",
|
166 | 166 | "metadata": {
|
167 | 167 | "id": "67ab8afa-f7c6-4fbf-b596-cb512da949da",
|
|
194 | 194 | },
|
195 | 195 | {
|
196 | 196 | "cell_type": "code",
|
197 |
| - "execution_count": 2, |
| 197 | + "execution_count": 4, |
198 | 198 | "id": "aac9563e",
|
199 | 199 | "metadata": {
|
200 | 200 | "id": "aac9563e",
|
|
208 | 208 | },
|
209 | 209 | {
|
210 | 210 | "cell_type": "code",
|
211 |
| - "execution_count": 3, |
| 211 | + "execution_count": 5, |
212 | 212 | "id": "a3c3999a",
|
213 | 213 | "metadata": {
|
214 | 214 | "id": "a3c3999a",
|
|
229 | 229 | },
|
230 | 230 | {
|
231 | 231 | "cell_type": "code",
|
232 |
| - "execution_count": 4, |
| 232 | + "execution_count": 6, |
233 | 233 | "id": "12eb86d8",
|
234 | 234 | "metadata": {
|
235 | 235 | "id": "12eb86d8",
|
|
271 | 271 | },
|
272 | 272 | {
|
273 | 273 | "cell_type": "code",
|
274 |
| - "execution_count": 5, |
| 274 | + "execution_count": 7, |
275 | 275 | "id": "5d076412",
|
276 | 276 | "metadata": {},
|
277 | 277 | "outputs": [
|
|
313 | 313 | },
|
314 | 314 | {
|
315 | 315 | "cell_type": "code",
|
316 |
| - "execution_count": 6, |
| 316 | + "execution_count": 8, |
317 | 317 | "id": "b2a4bd1b",
|
318 | 318 | "metadata": {},
|
319 | 319 | "outputs": [
|
|
345 | 345 | },
|
346 | 346 | {
|
347 | 347 | "cell_type": "code",
|
348 |
| - "execution_count": 8, |
| 348 | + "execution_count": 9, |
349 | 349 | "id": "f3d294ff",
|
350 | 350 | "metadata": {},
|
351 | 351 | "outputs": [
|
|
375 | 375 | },
|
376 | 376 | {
|
377 | 377 | "cell_type": "code",
|
378 |
| - "execution_count": 59, |
| 378 | + "execution_count": 10, |
379 | 379 | "id": "55b63a61",
|
380 | 380 | "metadata": {},
|
381 | 381 | "outputs": [
|
|
405 | 405 | },
|
406 | 406 | {
|
407 | 407 | "cell_type": "code",
|
408 |
| - "execution_count": 60, |
| 408 | + "execution_count": 11, |
409 | 409 | "id": "9b831b3d",
|
410 | 410 | "metadata": {},
|
411 | 411 | "outputs": [
|
|
435 | 435 | },
|
436 | 436 | {
|
437 | 437 | "cell_type": "code",
|
438 |
| - "execution_count": null, |
| 438 | + "execution_count": 12, |
439 | 439 | "id": "fb1482e7",
|
440 | 440 | "metadata": {},
|
441 | 441 | "outputs": [],
|
|
504 | 504 | "metadata": {},
|
505 | 505 | "source": [
|
506 | 506 | "# Retrieval Strategies\n",
|
507 |
| - "Elasticsearch has big advantages over other vector only databases from its ability to support a wide range of retrieval strategies. In this notebook we will configure `ElasticsearchStore` to support some of the most common retrieval strategies. \n", |
| 507 | + "Elasticsearch has big advantages over other vector only databases from its ability to support a wide range of retrieval strategies. In this notebook we will configure `ElasticsearchStore` to support some of the most common retrieval strategies. \n", |
508 | 508 | "\n",
|
509 |
| - "By default, `ElasticsearchStore` uses the `ApproxRetrievalStrategy`.\n", |
| 509 | + "By default, `ElasticsearchStore` uses the `DenseVectorStrategy` (was called `ApproxRetrievalStrategy` prior to version 0.2.0).\n", |
510 | 510 | "\n",
|
511 |
| - "## ApproxRetrievalStrategy\n", |
512 |
| - "This will return the top `k` most similar vectors to the query vector. The `k` parameter is set when the `ElasticsearchStore` is initialized. The default value is `10`." |
| 511 | + "## DenseVectorStrategy\n", |
| 512 | + "This will return the top `k` most similar vectors to the query vector. The `k` parameter is set when the `ElasticsearchStore` is initialized. The default value is `10`." |
513 | 513 | ]
|
514 | 514 | },
|
515 | 515 | {
|
516 | 516 | "cell_type": "code",
|
517 |
| - "execution_count": null, |
| 517 | + "execution_count": 13, |
518 | 518 | "id": "999b5ef5",
|
519 | 519 | "metadata": {},
|
520 | 520 | "outputs": [],
|
521 | 521 | "source": [
|
| 522 | + "from langchain_elasticsearch import DenseVectorStrategy\n", |
| 523 | + "\n", |
522 | 524 | "db = ElasticsearchStore.from_documents(\n",
|
523 | 525 | " docs,\n",
|
524 | 526 | " embeddings,\n",
|
525 | 527 | " es_url=\"http://localhost:9200\",\n",
|
526 | 528 | " index_name=\"test\",\n",
|
527 |
| - " strategy=ElasticsearchStore.ApproxRetrievalStrategy(),\n", |
| 529 | + " strategy=DenseVectorStrategy(),\n", |
528 | 530 | ")\n",
|
529 | 531 | "\n",
|
530 | 532 | "docs = db.similarity_search(\n",
|
|
537 | 539 | "id": "9b651be5",
|
538 | 540 | "metadata": {},
|
539 | 541 | "source": [
|
540 |
| - "### Example: Approx with hybrid\n", |
| 542 | + "### Example: Hybrid retrieval with dense vector and keyword search\n", |
541 | 543 | "This example will show how to configure `ElasticsearchStore` to perform a hybrid retrieval, using a combination of approximate semantic search and keyword based search. \n",
|
542 | 544 | "\n",
|
543 | 545 | "We use RRF to balance the two scores from different retrieval methods.\n",
|
544 | 546 | "\n",
|
545 |
| - "To enable hybrid retrieval, we need to set `hybrid=True` in `ElasticsearchStore` `ApproxRetrievalStrategy` constructor.\n", |
| 547 | + "To enable hybrid retrieval, we need to set `hybrid=True` in the `DenseVectorStrategy` constructor.\n", |
546 | 548 | "\n",
|
547 | 549 | "```python\n",
|
548 | 550 | "\n",
|
|
551 | 553 | " embeddings, \n",
|
552 | 554 | " es_url=\"http://localhost:9200\", \n",
|
553 | 555 | " index_name=\"test\",\n",
|
554 |
| - " strategy=ElasticsearchStore.ApproxRetrievalStrategy(\n", |
555 |
| - " hybrid=True,\n", |
556 |
| - " )\n", |
| 556 | + " strategy=DenseVectorStrategy(hybrid=True)\n", |
557 | 557 | ")\n",
|
558 | 558 | "```\n",
|
559 | 559 | "\n",
|
|
582 | 582 | "}\n",
|
583 | 583 | "```\n",
|
584 | 584 | "\n",
|
585 |
| - "### Example: Approx with Embedding Model in Elasticsearch\n", |
586 |
| - "This example will show how to configure `ElasticsearchStore` to use the embedding model deployed in Elasticsearch for approximate retrieval. \n", |
| 585 | + "### Example: Dense vector search with Embedding Model in Elasticsearch\n", |
| 586 | + "This example will show how to configure `ElasticsearchStore` to use the embedding model deployed in Elasticsearch for dense vector retrieval.\n", |
587 | 587 | "\n",
|
588 |
| - "To use this, specify the model_id in `ElasticsearchStore` `ApproxRetrievalStrategy` constructor via the `query_model_id` argument.\n", |
| 588 | + "To use this, specify the model_id in `DenseVectorStrategy` constructor via the `query_model_id` argument.\n", |
589 | 589 | "\n",
|
590 | 590 | "**NOTE** This requires the model to be deployed and running in Elasticsearch ml node. See [notebook example](https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/integrations/hugging-face/loading-model-from-hugging-face.ipynb) on how to deploy the model with eland.\n"
|
591 | 591 | ]
|
592 | 592 | },
|
593 | 593 | {
|
594 | 594 | "cell_type": "code",
|
595 |
| - "execution_count": null, |
| 595 | + "execution_count": 14, |
596 | 596 | "id": "0a0c85e7",
|
597 | 597 | "metadata": {},
|
598 | 598 | "outputs": [],
|
599 | 599 | "source": [
|
600 |
| - "APPROX_SELF_DEPLOYED_INDEX_NAME = \"test-approx-self-deployed\"\n", |
| 600 | + "DENSE_SELF_DEPLOYED_INDEX_NAME = \"test-dense-self-deployed\"\n", |
601 | 601 | "\n",
|
602 | 602 | "# Note: This does not have an embedding function specified\n",
|
603 | 603 | "# Instead, we will use the embedding model deployed in Elasticsearch\n",
|
604 | 604 | "db = ElasticsearchStore(\n",
|
605 | 605 | " es_cloud_id=\"<your cloud id>\",\n",
|
606 | 606 | " es_user=\"elastic\",\n",
|
607 | 607 | " es_password=\"<your password>\",\n",
|
608 |
| - " index_name=APPROX_SELF_DEPLOYED_INDEX_NAME,\n", |
| 608 | + " index_name=DENSE_SELF_DEPLOYED_INDEX_NAME,\n", |
609 | 609 | " query_field=\"text_field\",\n",
|
610 | 610 | " vector_query_field=\"vector_query_field.predicted_value\",\n",
|
611 |
| - " strategy=ElasticsearchStore.ApproxRetrievalStrategy(\n", |
612 |
| - " query_model_id=\"sentence-transformers__all-minilm-l6-v2\"\n", |
613 |
| - " ),\n", |
| 611 | + " strategy=DenseVectorStrategy(model_id=\"sentence-transformers__all-minilm-l6-v2\"),\n", |
614 | 612 | ")\n",
|
615 | 613 | "\n",
|
616 | 614 | "# Setup a Ingest Pipeline to perform the embedding\n",
|
|
631 | 629 | "# creating a new index with the pipeline,\n",
|
632 | 630 | "# not relying on langchain to create the index\n",
|
633 | 631 | "db.client.indices.create(\n",
|
634 |
| - " index=APPROX_SELF_DEPLOYED_INDEX_NAME,\n", |
| 632 | + " index=DENSE_SELF_DEPLOYED_INDEX_NAME,\n", |
635 | 633 | " mappings={\n",
|
636 | 634 | " \"properties\": {\n",
|
637 | 635 | " \"text_field\": {\"type\": \"text\"},\n",
|
|
655 | 653 | " es_cloud_id=\"<cloud id>\",\n",
|
656 | 654 | " es_user=\"elastic\",\n",
|
657 | 655 | " es_password=\"<cloud password>\",\n",
|
658 |
| - " index_name=APPROX_SELF_DEPLOYED_INDEX_NAME,\n", |
| 656 | + " index_name=DENSE_SELF_DEPLOYED_INDEX_NAME,\n", |
659 | 657 | " query_field=\"text_field\",\n",
|
660 | 658 | " vector_query_field=\"vector_query_field.predicted_value\",\n",
|
661 |
| - " strategy=ElasticsearchStore.ApproxRetrievalStrategy(\n", |
662 |
| - " query_model_id=\"sentence-transformers__all-minilm-l6-v2\"\n", |
663 |
| - " ),\n", |
| 659 | + " strategy=DenseVectorStrategy(model_id=\"sentence-transformers__all-minilm-l6-v2\"),\n", |
664 | 660 | ")\n",
|
665 | 661 | "\n",
|
666 | 662 | "# Perform search\n",
|
|
672 | 668 | "id": "53959de6",
|
673 | 669 | "metadata": {},
|
674 | 670 | "source": [
|
675 |
| - "## SparseVectorRetrievalStrategy (ELSER)\n", |
| 671 | + "## SparseVectorStrategy (ELSER)\n", |
676 | 672 | "This strategy uses Elasticsearch's sparse vector retrieval to retrieve the top-k results. We only support our own \"ELSER\" embedding model for now.\n",
|
677 | 673 | "\n",
|
678 | 674 | "**NOTE** This requires the ELSER model to be deployed and running in Elasticsearch ml node. \n",
|
679 | 675 | "\n",
|
680 |
| - "To use this, specify `SparseVectorRetrievalStrategy` in `ElasticsearchStore` constructor." |
| 676 | + "To use this, specify `SparseVectorStrategy` (was called `SparseVectorRetrievalStrategy` prior to version 0.2.0) in the `ElasticsearchStore` constructor. You will need to provide a model ID." |
681 | 677 | ]
|
682 | 678 | },
|
683 | 679 | {
|
|
695 | 691 | }
|
696 | 692 | ],
|
697 | 693 | "source": [
|
| 694 | + "from langchain_elasticsearch import SparseVectorStrategy\n", |
| 695 | + "\n", |
698 | 696 | "# Note that this example doesn't have an embedding function. This is because we infer the tokens at index time and at query time within Elasticsearch.\n",
|
699 | 697 | "# This requires the ELSER model to be loaded and running in Elasticsearch.\n",
|
700 | 698 | "db = ElasticsearchStore.from_documents(\n",
|
701 | 699 | " docs,\n",
|
702 |
| - " es_cloud_id=\"My_deployment:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvOjQ0MyQ2OGJhMjhmNDc1M2Y0MWVjYTk2NzI2ZWNkMmE5YzRkNyQ3NWI4ODRjNWQ2OTU0MTYzODFjOTkxNmQ1YzYxMGI1Mw==\",\n", |
| 700 | + " es_cloud_id=\"<cloud id>\",\n", |
703 | 701 | " es_user=\"elastic\",\n",
|
704 |
| - " es_password=\"GgUPiWKwEzgHIYdHdgPk1Lwi\",\n", |
| 702 | + " es_password=\"<cloud password>\",\n", |
705 | 703 | " index_name=\"test-elser\",\n",
|
706 |
| - " strategy=ElasticsearchStore.SparseVectorRetrievalStrategy(),\n", |
| 704 | + " strategy=SparseVectorStrategy(model_id=\".elser_model_2\"),\n", |
707 | 705 | ")\n",
|
708 | 706 | "\n",
|
709 | 707 | "db.client.indices.refresh(index=\"test-elser\")\n",
|
|
719 | 717 | "id": "edf3a093",
|
720 | 718 | "metadata": {},
|
721 | 719 | "source": [
|
722 |
| - "## ExactRetrievalStrategy\n", |
723 |
| - "This strategy uses Elasticsearch's exact retrieval (also known as brute force) to retrieve the top-k results.\n", |
| 720 | + "## DenseVectorScriptScoreStrategy\n", |
| 721 | + "This strategy uses Elasticsearch's script score query to perform exact vector retrieval (also known as brute force) to retrieve the top-k results. (This strategy was called `ExactRetrievalStrategy` prior to version 0.2.0.)\n", |
724 | 722 | "\n",
|
725 |
| - "To use this, specify `ExactRetrievalStrategy` in `ElasticsearchStore` constructor.\n", |
| 723 | + "To use this, specify `DenseVectorScriptScoreStrategy` in `ElasticsearchStore` constructor.\n", |
726 | 724 | "\n",
|
727 | 725 | "```python\n",
|
| 726 | + "from langchain_elasticsearch import SparseVectorStrategy\n", |
728 | 727 | "\n",
|
729 | 728 | "db = ElasticsearchStore.from_documents(\n",
|
730 | 729 | " docs, \n",
|
731 | 730 | " embeddings, \n",
|
732 | 731 | " es_url=\"http://localhost:9200\", \n",
|
733 | 732 | " index_name=\"test\",\n",
|
734 |
| - " strategy=ElasticsearchStore.ExactRetrievalStrategy()\n", |
| 733 | + " strategy=DenseVectorScriptScoreStrategy(),\n", |
| 734 | + ")\n", |
| 735 | + "```" |
| 736 | + ] |
| 737 | + }, |
| 738 | + { |
| 739 | + "cell_type": "markdown", |
| 740 | + "id": "11b51c47", |
| 741 | + "metadata": {}, |
| 742 | + "source": [ |
| 743 | + "## BM25Strategy\n", |
| 744 | + "Finally, you can use full-text keyword search.\n", |
| 745 | + "\n", |
| 746 | + "To use this, specify `BM25Strategy` in `ElasticsearchStore` constructor.\n", |
| 747 | + "\n", |
| 748 | + "```python\n", |
| 749 | + "from langchain_elasticsearch import BM25Strategy\n", |
| 750 | + "\n", |
| 751 | + "db = ElasticsearchStore.from_documents(\n", |
| 752 | + " docs, \n", |
| 753 | + " es_url=\"http://localhost:9200\", \n", |
| 754 | + " index_name=\"test\",\n", |
| 755 | + " strategy=BM25Strategy(),\n", |
735 | 756 | ")\n",
|
736 | 757 | "```"
|
737 | 758 | ]
|
|
924 | 945 | "\n",
|
925 | 946 | "## What's new?\n",
|
926 | 947 | "\n",
|
927 |
| - "The new implementation is now one class called `ElasticsearchStore` which can be used for approx, exact, and ELSER search retrieval, via strategies.\n", |
| 948 | + "The new implementation is now one class called `ElasticsearchStore` which can be used for approximate dense vector, exact dense vector, sparse vector (ELSER), BM25 retrieval and hybrid retrieval, via strategies.\n", |
928 | 949 | "\n",
|
929 |
| - "## Im using ElasticKNNSearch\n", |
| 950 | + "## I am using ElasticKNNSearch\n", |
930 | 951 | "\n",
|
931 | 952 | "Old implementation:\n",
|
932 | 953 | "\n",
|
|
946 | 967 | "\n",
|
947 | 968 | "```python\n",
|
948 | 969 | "\n",
|
949 |
| - "from langchain_elasticsearch import ElasticsearchStore\n", |
| 970 | + "from langchain_elasticsearch import ElasticsearchStore, DenseVectorStrategy\n", |
950 | 971 | "\n",
|
951 | 972 | "db = ElasticsearchStore(\n",
|
952 | 973 | " es_url=\"http://localhost:9200\",\n",
|
953 | 974 | " index_name=\"test_index\",\n",
|
954 | 975 | " embedding=embedding,\n",
|
955 | 976 | " # if you use the model_id\n",
|
956 |
| - " # strategy=ElasticsearchStore.ApproxRetrievalStrategy( query_model_id=\"test_model\" )\n", |
| 977 | + " # strategy=DenseVectorStrategy(model_id=\"test_model\")\n", |
957 | 978 | " # if you use hybrid search\n",
|
958 |
| - " # strategy=ElasticsearchStore.ApproxRetrievalStrategy( hybrid=True )\n", |
| 979 | + " # strategy=DenseVectorStrategy(hybrid=True)\n", |
959 | 980 | ")\n",
|
960 | 981 | "\n",
|
961 | 982 | "```\n",
|
962 | 983 | "\n",
|
963 |
| - "## Im using ElasticVectorSearch\n", |
| 984 | + "## I am using ElasticVectorSearch\n", |
964 | 985 | "\n",
|
965 | 986 | "Old implementation:\n",
|
966 | 987 | "\n",
|
|
980 | 1001 | "\n",
|
981 | 1002 | "```python\n",
|
982 | 1003 | "\n",
|
983 |
| - "from langchain_elasticsearch import ElasticsearchStore\n", |
| 1004 | + "from langchain_elasticsearch import ElasticsearchStore, DenseVectorScriptScoreStrategy\n", |
984 | 1005 | "\n",
|
985 | 1006 | "db = ElasticsearchStore(\n",
|
986 | 1007 | " es_url=\"http://localhost:9200\",\n",
|
987 | 1008 | " index_name=\"test_index\",\n",
|
988 | 1009 | " embedding=embedding,\n",
|
989 |
| - " strategy=ElasticsearchStore.ExactRetrievalStrategy()\n", |
| 1010 | + " strategy=DenseVectorScriptScoreStrategy()\n", |
990 | 1011 | ")\n",
|
991 | 1012 | "\n",
|
992 | 1013 | "```"
|
|
0 commit comments