
    Q
i9                     :   d dl Z d dlmZmZmZmZmZmZ d dlm	Z	m
Z
mZmZ d dlmZmZ d dlmZ d dlmZ d dlmZ d dlmZ d d	lmZ d d
lmZ  ed          Z ed          Z G d de	          Z G d de          Z G d de          Z  G d de          Z!dS )    N)AnyDictListOptionalSetUnion)	BaseModelFieldfield_validatormodel_validator)AggregateRequestDesc)Self)FilterExpression)array_to_buffer)VectorDataType)FullTextQueryHelper)lazy_importnltkznltk.corpus.stopwordsc                   :   e Zd ZU dZeee         ef         ed<   e	ed<   dZ
e	ed<   dZeed<    edd	d
          Zeed<    ed          ede	de	fd                        Z ed          ededefd                        Z ed          defd            ZdS )Vectora  
    Simple object containing the necessary arguments to perform a multi vector query.

    Args:
    vector: The vector values as a list of floats or bytes
    field_name: The name of the vector field to search
    dtype: The data type of the vector (default: "float32")
    weight: The weight for this vector in the combined score (default: 1.0)
    max_distance: The maximum distance for vector range search (default: 2.0, range: [0.0, 2.0])
    vector
field_namefloat32dtypeg      ?weight       @        )defaultgelemax_distancereturnc                     	 t          |                                           n2# t          $ r% t          d| dd t           D                        w xY w|S )NzInvalid data type: z. Supported types are: c                 6    g | ]}|                                 S  )lower).0ts     C:\Users\Dell Inspiron 16\Desktop\tws\AgrotaPowerBi\back-agrota-powerbi\mcp-client-agrota\venv\Lib\site-packages\redisvl/query/aggregate.py
<listcomp>z)Vector.validate_dtype.<locals>.<listcomp>+   s!    DgDgDgSTQWWYYDgDgDg    )r   upper
ValueError)clsr   s     r*   validate_dtypezVector.validate_dtype$   sw    	5;;==)))) 	 	 	ieiiDgDgXfDgDgDgii  	 s	   !$ /Ac                     t          |t          t          f          st          d          |dk     s|dk    rt          d          |S )Nz0max_distance must be a value between 0.0 and 2.0r   r   )
isinstancefloatintr.   )r/   r"   s     r*   validate_max_distancezVector.validate_max_distance/   sT     ,55 	QOPPP#!3!3OPPPr,   after)modec                 |    t          | j        t                    r| S t          | j        | j                  | _        | S )zIIf the vector passed in is an array of float convert it to a byte string.)r2   r   bytesr   r   selfs    r*   validate_vectorzVector.validate_vector8   s7     dk5)) 	K%dk4:>>r,   N)__name__
__module____qualname____doc__r   r   r3   r9   __annotations__strr   r   r
   r"   r   classmethodr0   r5   r   r   r<   r&   r,   r*   r   r      s?        	 	 $u+u$%%%%OOOE3FE%<<<L%<<<_W3 3    [  _^$$ 5    [ %$ _'"""    #"  r,   r   c                   "     e Zd ZdZ fdZ xZS )AggregationQueryzZ
    Base class for aggregation queries used to create aggregation queries for Redis.
    c                 J    t                                          |           d S )N)super__init__)r;   query_string	__class__s     r*   rH   zAggregationQuery.__init__F   s!    &&&&&r,   )r=   r>   r?   r@   rH   __classcell__rJ   s   @r*   rE   rE   A   sB         ' ' ' ' ' ' ' ' 'r,   rE   c                       e Zd ZU dZdZeed<   dZeed<   	 	 	 	 	 	 	 	 	 d"dededee	e
e         f         dededeeeef                  dedededee
e                  deeeee         f                  dedeeeef                  f fdZedeeef         fd            Zedee         fd            Zedeeef         fd            Zdeeef         fdZdefd Zdefd!Z xZS )#AggregateHybridQuerya  
    AggregateHybridQuery combines text and vector search in Redis.
    It allows you to perform a hybrid search using both text and vector similarity.
    It scores documents based on a weighted combination of text and vector similarity.

    .. code-block:: python

        from redisvl.query import AggregateHybridQuery
        from redisvl.index import SearchIndex

        index = SearchIndex.from_yaml("path/to/index.yaml")

        query = AggregateHybridQuery(
            text="example text",
            text_field_name="text_field",
            vector=[0.1, 0.2, 0.3],
            vector_field_name="vector_field",
            text_scorer="BM25STD",
            filter_expression=None,
            alpha=0.7,
            dtype="float32",
            num_results=10,
            return_fields=["field1", "field2"],
            stopwords="english",
            dialect=2,
        )

        results = index.query(query)

    vector_distanceDISTANCE_IDr   VECTOR_PARAMBM25STDNffffff?r   
   english   texttext_field_namevector_field_nametext_scorerfilter_expressionalphar   num_resultsreturn_fields	stopwordsdialecttext_weightsc                    |                                 st          d          || _        || _        || _        || _        || _        || _        || _        |	| _	        t          ||          | _        |                                 }t                                          |           |                     |           |                                  |                     d| j         dd           |                     d|z
   d| d	
           |                     t)          d          |	           |                     |           |
r | j        |
  dS dS )a
  
        Instantiates a AggregateHybridQuery object.

        Args:
            text (str): The text to search for.
            text_field_name (str): The text field name to search in.
            vector (Union[bytes, List[float]]): The vector to perform vector similarity search.
            vector_field_name (str): The vector field name to search in.
            text_scorer (str, optional): The text scorer to use. Options are {TFIDF, TFIDF.DOCNORM,
                BM25, DISMAX, DOCSCORE, BM25STD}. Defaults to "BM25STD".
            filter_expression (Optional[FilterExpression], optional): The filter expression to use.
                Defaults to None.
            alpha (float, optional): The weight of the vector similarity. Documents will be scored
                as: hybrid_score = (alpha) * vector_score + (1-alpha) * text_score.
                Defaults to 0.7.
            dtype (str, optional): The data type of the vector. Defaults to "float32".
            num_results (int, optional): The number of results to return. Defaults to 10.
            return_fields (Optional[List[str]], optional): The fields to return. Defaults to None.
            stopwords (Optional[Union[str, Set[str]]], optional): The stopwords to remove from the
                provided text prior to search-use. If a string such as "english" "german" is
                provided then a default set of stopwords for that language will be used. if a list,
                set, or tuple of strings is provided then those will be used as stopwords.
                Defaults to "english". if set to "None" then no stopwords will be removed.

                Note: This parameter controls query-time stopword filtering (client-side).
                For index-level stopwords configuration (server-side), see IndexInfo.stopwords.
                Using query-time stopwords with index-level STOPWORDS 0 is counterproductive.
            dialect (int, optional): The Redis dialect version. Defaults to 2.
            text_weights (Optional[Dict[str, float]]): The importance weighting of individual words
                within the query text. Defaults to None, as no modifications will be made to the
                text_scorer score.

        Note:
            AggregateHybridQuery uses FT.AGGREGATE commands which do NOT support runtime
            parameters. For runtime parameter support (ef_runtime, search_window_size, etc.),
            use VectorQuery or VectorRangeQuery which use FT.SEARCH commands.

        Raises:
            ValueError: If the text string is empty, or if the text string becomes empty after
                stopwords are removed.
            TypeError: If the stopwords are not a set, list, or tuple of strings.
        ztext string cannot be empty)r_   ra   z(2 - @)/2z@__score)vector_similarity
text_score   z*@text_score + z*@vector_similarity)hybrid_scorez@hybrid_scoremaxN)stripr.   _text_text_field_vector_vector_field_filter_expression_alpha_dtype_num_resultsr   
_ft_helper_build_query_stringrG   rH   scorer
add_scoresapplyrP   sort_byr   r`   load)r;   rW   rX   r   rY   rZ   r[   r\   r   r]   r^   r_   r`   ra   rI   rJ   s                  r*   rH   zAggregateHybridQuery.__init__m   sz   v zz|| 	<:;;;
*."3'-%
 
 

 //11&&&K   

<t'7<<< 	 	
 	
 	
 	

1U7 U U5 U U U
VVVT/**<<<W 	&DI}%%%%	& 	&r,   r#   c                     t          | j        t                    rt          | j        | j                  }n| j        }| j        |i}|S )Return the parameters for the aggregation.

        Returns:
            Dict[str, Any]: The parameters for the aggregation.
        )r   )r2   rm   listr   rq   rQ   )r;   r   paramss      r*   r}   zAggregateHybridQuery.params   sI     dlD)) 	"$T\EEEFF\F"&"3V!<r,   c                     | j         j        S )zxReturn the stopwords used in the query.
        Returns:
            Set[str]: The stopwords used in the query.
        )rs   r_   r:   s    r*   r_   zAggregateHybridQuery.stopwords   s     ((r,   c                     | j         j        S )z`Get the text weights.

        Returns:
            Dictionary of word:weight mappings.
        )rs   ra   r:   s    r*   ra   z!AggregateHybridQuery.text_weights   s     ++r,   weightsc                 l    | j                             |           |                                 | _        dS )z}Set or update the text weights for the query.

        Args:
            weights: Dictionary of word:weight mappings
        N)rs   set_text_weightsrt   _query)r;   r   s     r*   r   z%AggregateHybridQuery.set_text_weights   s1     	((111..00r,   c                     | j                             | j        | j        | j                  }d| j         d| j         d| j         }|d| j         z  }| d| dS )DBuild the full query string for text search with optional filtering.zKNN z @z $z AS z=>[])	rs   build_query_stringrk   rl   ro   rr   rn   rQ   rP   )r;   rW   	knn_querys      r*   rt   z(AggregateHybridQuery._build_query_string   s    11J($*A
 
 R4$QQ(:QQd>OQQ 	
 	.D,...	''9''''r,   c                 d    d                     d |                                 D                       S ).Return the string representation of the query. c                 ,    g | ]}t          |          S r&   rB   r(   xs     r*   r+   z0AggregateHybridQuery.__str__.<locals>.<listcomp>      ;;;AQ;;;r,   join
build_argsr:   s    r*   __str__zAggregateHybridQuery.__str__  -    xx;;):):;;;<<<r,   )	rR   NrS   r   rT   NrU   rV   N)r=   r>   r?   r@   rP   rB   rA   rQ   r   r9   r   r3   r   r   r4   r   r   rH   propertyr   r}   r_   ra   r   rt   r   rK   rL   s   @r*   rN   rN   J   sM         > )K((( L#    %DH-14=37X& X&X& X& eT%[()	X&
 X& X& $E#/?*?$@AX& X& X& X&  S	*X& E#s3x-01X& X& tCJ/0X& X& X& X& X& X&t S#X    X )3s8 ) ) ) X) ,d3:. , , , X,1S%Z(8 1 1 1 1(S ( ( ( ( = = = = = = = = =r,   rN   c                        e Zd ZU dZee         ed<   	 	 	 	 ddeeee         f         deee	                  deee	e
f                  d	ed
ef
 fdZedee	ef         fd            Zde	fdZde	fdZ xZS )MultiVectorQueryaJ  
    MultiVectorQuery allows for search over multiple vector fields in a document simultaneously.
    The final score will be a weighted combination of the individual vector similarity scores
    following the formula:

    score = (w_1 * score_1 + w_2 * score_2 + w_3 * score_3 + ... )

    Vectors may be of different size and datatype, but must be indexed using the 'cosine' distance_metric.

    .. code-block:: python

        from redisvl.query import MultiVectorQuery, Vector
        from redisvl.index import SearchIndex

        index = SearchIndex.from_yaml("path/to/index.yaml")

        vector_1 = Vector(
            vector=[0.1, 0.2, 0.3],
            field_name="text_vector",
            dtype="float32",
            weight=0.7,
        )
        vector_2 = Vector(
            vector=[0.5, 0.5],
            field_name="image_vector",
            dtype="bfloat16",
            weight=0.2,
        )
        vector_3 = Vector(
            vector=[0.1, 0.2, 0.3],
            field_name="text_vector",
            dtype="float64",
            weight=0.5,
        )

        query = MultiVectorQuery(
            vectors=[vector_1, vector_2, vector_3],
            filter_expression=None,
            num_results=10,
            return_fields=["field1", "field2"],
            dialect=2,
        )

        results = index.query(query)
    _vectorsNrT   rV   vectorsr^   r[   r]   r`   c           	         || _         || _        t          |t                    r	|g| _        n|| _        t          d | j        D                       st          d          |                                 }t                      	                    |           t          t          | j                            D ]} | j        di d| d| di g }t          d | j        D                       D ] \  }}	|                    d| d|	            !d	                    |          }
|                     |

           |                     t#          d          |           |                     |           |r | j        |  dS dS )a@  
        Instantiates a MultiVectorQuery object.

        Args:
            vectors (Union[Vector, List[Vector]]): The Vectors to perform vector similarity search.
            return_fields (Optional[List[str]], optional): The fields to return. Defaults to None.
            filter_expression (Optional[Union[str, FilterExpression]]): The filter expression to use.
                Defaults to None.
            num_results (int, optional): The number of results to return. Defaults to 10.
            dialect (int, optional): The Redis dialect version. Defaults to 2.
        c                 8    g | ]}t          |t                    S r&   )r2   r   r(   vs     r*   r+   z-MultiVectorQuery.__init__.<locals>.<listcomp>S  s"    AAAaJq&))AAAr,   zBvector argument must be a Vector object or list of Vector objects.score_z(2 - @distance_rc   c                     g | ]	}|j         
S r&   )r   r   s     r*   r+   z-MultiVectorQuery.__init__.<locals>.<listcomp>a  s    ???Aqx???r,   z@score_z * z + )combined_scorez@combined_scorerh   Nr&   )ro   rr   r2   r   r   all	TypeErrorrt   rG   rH   rangelenrw   	enumerateappendr   rx   r   r`   ry   )r;   r   r^   r[   r]   r`   rI   icombined_scoreswcombined_score_stringrJ   s              r*   rH   zMultiVectorQuery.__init__7  s   ( #4'gv&& 	$$IDMM#DMAA4=AAABB 	T   //11&&& s4=))** 	C 	CADJBB,1,,(@!(@(@(@ABBBB ?????@@ 	8 	8DAq""#6Q#6#61#6#67777 %

? ; ;

"7
888T+,,+>>>W 	&DI}%%%%	& 	&r,   r#   c                 X    i }t          | j                  D ]\  }}|j        |d| <   |S )r{   vector_)r   r   r   )r;   r}   r   r   s       r*   r}   zMultiVectorQuery.paramsl  s@     dm,, 	- 	-DAq$%HF=Q==!!r,   c                 J   g }t          d | j        D                       D ]+\  }\  }}}|                    d| d| d| d| d	           ,d                    |          }| j        }t          | j        t                    rt          | j                  }|r	d| d	| d
S | S )r   c                 6    g | ]}|j         |j        |j        fS r&   )r   r   r"   r   s     r*   r+   z8MultiVectorQuery._build_query_string.<locals>.<listcomp>~  s%    MMM!ahan5MMMr,   @z:[VECTOR_RANGE z	 $vector_z!]=>{$YIELD_DISTANCE_AS: distance_}z AND (z) AND ())r   r   r   r   ro   r2   r   rB   )r;   range_queriesr   r   fieldmax_distrange_queryr[   s           r*   rt   z$MultiVectorQuery._build_query_stringx  s     ,5MMt}MMM-
 -
 	 	(A(x   gEgg(ggQggbcggg    ll=11 3d-/?@@ 	= #D$; < < 	$?{??+<????!##r,   c                 d    d                     d |                                 D                       S )r   r   c                 ,    g | ]}t          |          S r&   r   r   s     r*   r+   z,MultiVectorQuery.__str__.<locals>.<listcomp>  r   r,   r   r:   s    r*   r   zMultiVectorQuery.__str__  r   r,   )NNrT   rV   )r=   r>   r?   r@   r   r   rA   r   r   rB   r   r4   rH   r   r   r   r}   rt   r   rK   rL   s   @r*   r   r     s,        , ,\ 6l
 .2DH3& 3&vtF|+,3&  S	*3& $E#/?*?$@A	3&
 3& 3& 3& 3& 3& 3& 3&j 	S#X 	 	 	 X	$S $ $ $ $.= = = = = = = = =r,   r   )"warningstypingr   r   r   r   r   r   pydanticr	   r
   r   r   !redis.commands.search.aggregationr   r   typing_extensionsr   redisvl.query.filterr   redisvl.redis.utilsr   redisvl.schema.fieldsr   $redisvl.utils.full_text_query_helperr   redisvl.utils.utilsr   r   nltk_stopwordsr   rE   rN   r   r&   r,   r*   <module>r      s    8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 G G G G G G G G G G G G D D D D D D D D " " " " " " 1 1 1 1 1 1 / / / / / / 0 0 0 0 0 0 D D D D D D + + + + + +{6455, , , , ,Y , , ,^' ' ' ' '' ' ' 'y= y= y= y= y=+ y= y= y=xK= K= K= K= K=' K= K= K= K= K=r,   