|
12 | 12 |
|
13 | 13 | from feast import Entity, FeatureView |
14 | 14 | from feast.field import Field |
15 | | -from feast.filter_models import ComparisonFilter |
| 15 | +from feast.filter_models import ComparisonFilter, CompoundFilter |
16 | 16 | from feast.infra.online_stores.milvus_online_store.milvus import ( |
17 | 17 | PLACEHOLDER_VECTOR_DIM, |
18 | 18 | PLACEHOLDER_VECTOR_FIELD, |
@@ -746,3 +746,103 @@ def test_warns_when_existing_collection_lacks_partition_key( |
746 | 746 |
|
747 | 747 | assert "created without partition key 'brand_id'" in caplog.text |
748 | 748 | mock_client.create_collection.assert_not_called() |
| 749 | + |
| 750 | + |
| 751 | +def test_online_delete_by_entity_key_and_by_filter(tmp_path: Path) -> None: |
| 752 | + config = _lite_config(tmp_path) |
| 753 | + fv = _scalar_feature_view() |
| 754 | + store = MilvusOnlineStore() |
| 755 | + store.update(config, [], [fv], [], [], partial=False) |
| 756 | + _write_rows( |
| 757 | + store, |
| 758 | + config, |
| 759 | + fv, |
| 760 | + { |
| 761 | + driver_id: { |
| 762 | + "trips_today": ValueProto(float_val=float(driver_id)), |
| 763 | + "city": ValueProto(string_val=city), |
| 764 | + } |
| 765 | + for driver_id, city in [(1, "Paris"), (2, "Rome"), (3, "Rome")] |
| 766 | + }, |
| 767 | + ) |
| 768 | + |
| 769 | + store.online_delete(config, fv, [_entity_key(1)]) |
| 770 | + rows = _read(store, config, fv, [1, 2, 3], ["city"]) |
| 771 | + assert [row is None for row in rows] == [True, False, False] |
| 772 | + |
| 773 | + store.online_delete( |
| 774 | + config, fv, filters=ComparisonFilter(type="eq", key="city", value="Rome") |
| 775 | + ) |
| 776 | + assert _read(store, config, fv, [1, 2, 3], ["city"]) == [None, None, None] |
| 777 | + |
| 778 | + # No tombstone is kept, so the row can be written again. |
| 779 | + _write_rows( |
| 780 | + store, |
| 781 | + config, |
| 782 | + fv, |
| 783 | + { |
| 784 | + 1: { |
| 785 | + "trips_today": ValueProto(float_val=4.0), |
| 786 | + "city": ValueProto(string_val="Oslo"), |
| 787 | + } |
| 788 | + }, |
| 789 | + ) |
| 790 | + rows = _read(store, config, fv, [1], ["city"]) |
| 791 | + assert rows[0] is not None and rows[0]["city"].string_val == "Oslo" |
| 792 | + |
| 793 | + |
| 794 | +@pytest.mark.parametrize( |
| 795 | + "kwargs", |
| 796 | + [ |
| 797 | + {}, |
| 798 | + { |
| 799 | + "entity_keys": [_entity_key(1)], |
| 800 | + "filters": ComparisonFilter(type="eq", key="city", value="Rome"), |
| 801 | + }, |
| 802 | + {"filters": CompoundFilter(type="and", filters=[])}, |
| 803 | + { |
| 804 | + "filters": CompoundFilter( |
| 805 | + type="and", |
| 806 | + filters=[ |
| 807 | + ComparisonFilter(type="eq", key="brand_id", value="acme"), |
| 808 | + CompoundFilter(type="or", filters=[]), |
| 809 | + ], |
| 810 | + ) |
| 811 | + }, |
| 812 | + ], |
| 813 | +) |
| 814 | +def test_online_delete_rejects_ambiguous_and_unbounded_calls( |
| 815 | + kwargs: Dict[str, Any], |
| 816 | +) -> None: |
| 817 | + store = MilvusOnlineStore() |
| 818 | + store.client = MagicMock() |
| 819 | + |
| 820 | + with pytest.raises(ValueError): |
| 821 | + store.online_delete(_mock_config(), _scalar_feature_view(), **kwargs) |
| 822 | + |
| 823 | + store.client.delete.assert_not_called() |
| 824 | + |
| 825 | + |
| 826 | +@patch(f"{MILVUS_MODULE}.MilvusClient") |
| 827 | +def test_online_delete_does_not_create_a_missing_collection( |
| 828 | + mock_client_cls: MagicMock, |
| 829 | +) -> None: |
| 830 | + mock_client = _mock_client(mock_client_cls, has_collection=False) |
| 831 | + store = MilvusOnlineStore() |
| 832 | + |
| 833 | + store.online_delete(_mock_config(), _scalar_feature_view(), [_entity_key(1)]) |
| 834 | + store.online_delete(_mock_config(), _scalar_feature_view(), []) |
| 835 | + |
| 836 | + mock_client.create_collection.assert_not_called() |
| 837 | + mock_client.delete.assert_not_called() |
| 838 | + |
| 839 | + |
| 840 | +@patch(f"{MILVUS_MODULE}.MilvusClient") |
| 841 | +def test_online_delete_with_no_entity_keys_sends_nothing( |
| 842 | + mock_client_cls: MagicMock, |
| 843 | +) -> None: |
| 844 | + MilvusOnlineStore().online_delete( |
| 845 | + _mock_config(), _scalar_feature_view(), entity_keys=[] |
| 846 | + ) |
| 847 | + |
| 848 | + mock_client_cls.assert_not_called() |
0 commit comments