
    i                       d dl Z d dlZd dlZd dlmZ d dlmZmZmZm	Z	 d dl
mZmZmZ d dl
Z
d dlZd dlZd dlZd dlT d dlmZ d dlZd dlZd dlZd dlZd dlZd dlZd dlZd dlmZ  ej                    Zg dZ g d	Z!g d
Z"e"g dz  Z"e"g dz  Z"e"dgz  Z"e"g dz  Z"g dZ#g dZ$ e%e e!z   e"z   e$z   e#z             Z"g dZ&g dZ' e%e e!z   e$z             Z(g dZ)ddZ*ddZ+ G d dej        j,        j-                  Z-dS )    N)
namedtuple)ListSetDictOptional)	dataclassfieldfields)*)SQLAlchemyDataDriver)BeautifulSoup)   и   в   во   не   что   он   на   я   с   со   как   а   то   все   она   так   его   но   да   ты   к   у   же   вы   за   бы   по   только   ее   мне   было   вот   от   меня   еще   нет   о   из   ему   теперь
   когда   даже   ну
   вдруг   ли   если   уже   или   ни   быть   был   него   до   вас   нибудь
   опять   уж   вам   ведь   там
   потом   себя   ничего   ей
   может   они   тут   где   есть   надо   ней   для   мы   тебя   их   чем   была   сам   чтоб   без
   будто   чего   раз   тоже   себе   под
   будет   ж
   тогда   кто   этот   того   потому
   этого
   какой   совсем   ним
   здесь   этом   один
   почти   мой   тем
   чтобы   нее   сейчас   были   куда
   зачем   всех   никогда
   можно   при   наконецu   два   об   другой   хоть
   после   надu   больше   тот
   через   эти   нас   про
   всего   них
   какаяu
   много
   развеu   три   эту   моя   впрочемu   хорошо   свою   этой
   перед   иногда
   лучше   чуть   томu   нельзя
   такой   им
   более   всегда   конечно   всю
   между)imemymyselfweourours	ourselvesyouyouryoursyourself
yourselveshehimhishimselfsheherhersherselfititsitselftheythemtheirtheirs
themselveswhatwhichwhowhomthisthatthesethoseamisarewaswerebebeenbeinghavehashadhavingdodoesdiddoingaantheandbutiforbecauseasuntilwhileofatbyforwithaboutagainstbetweenintothroughduringbeforeafterabovebelowtofromupdowninoutonoffoverunderagainfurtherthenonceheretherewhenwherewhyhowallanybotheachfewmoremostothersomesuchnonornotonlyownsamesothantooverystcanwilljustdonshouldnow)u
   сделаu   делu   сделu   дела   этr   r   r   r   r   r   r   r   r   r   r   r   u   всёr   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r   r   r?   r-   r.   r   u   ещёr1   r2   r3   r   r5   r6   r7   r8   r9   r:   r;   r<   r=   r>   r?   r?   r   rB   r%   rD   u   нибытьrE   rF   r%   rH   rI   rJ   rK   rL   r   u   мочьrO   rP   rQ   rR   rS   r   rU   rV   r!   rO   rY   r?   r[   r\   r]   r^   r   r`   ra   rK   rc   r?   re   rf   rg   rh   r   rj      этоrl   rm   rO   ro   r  rq   rr   rs   rt   ru   r   rw   r?   ry   rz      весьr|   r}   r~   r   r2   r   r   r   r   r   r   rh   rV   r   r   rO   rl   r   rh   rs   r   u   свойrh   r   r   r   r   r   rO   r   r   r   r   r   ).u
   такоеri   r   r   r   rW   rM   rZ   r   rd   r   r+   r4   rn   rA   r0   r   r   rk   rb   r{   r   rG   r   rN   rC   r*   r   r   rp   rx   r/   r   rT   r   r   r,   r   rX   rD   r   r   r_   r@   r   rv   )u
   нужноu   хотяu   затоu   именноu   вообщеu   тудаu   такиu   делатьu   помнитьu
   менееu   оноu
   кромеu   твойu   откудаu   считать   внеu   тойu   каждыйu
   никтоu   которыйu
   затемu   вопросu   обаu   длит)rl   r   u   ещu   нибu   мочr  r     веr"  u   своr"  r   u   нужнu   хот   затu
   вообщu   тудr   u   менr   u   кромu   твоr!  r   u   каждu   никтu
   которr#  r   )	r   rl   u   почемуry   rg   rQ   r6   u   можешьrY   )docwwwhttphttpsmailto)u
   авторu   бизнес-процессu   владелецu   датu   исполнителu   контрагентu   логическu
   отделu   постановщикu   приоритетu   проектu   процессu
   спискu   стандартнu   статусu   тип)approvbaseclosedefaultdocumentopentasku   бизнесu   документu
   задачu   задачаu   закрытu
   обычнu   системu   созданu   черновик)textml_textnametagscommentsaddon_fieldskey_phrasesc                 ,   ddl m}m} ddlm}  ||           }|                                D ]/\  }}||j        vr|                     |||                    }0t          |	                    |
                                ddi                    S )Nr   )r0  	bindparam)
postgresql)valueliteral_bindsT)dialectcompile_kwargs)sqlalchemy.sqlr0  r8  sqlalchemy.dialectsr9  items_bindparams
bindparamsstrcompiler<  )sqlparamsr0  r8  r9  stmtkvs           ./cmf/models/cmf_full_search.pysql_debug_not_workrK  ?   s    ..............499D||~~ 4 4!D$$$__YYq22233t||J$6$6$8$8Z^H_|``aaa    c                 (   | }|                                 D ]z\  }}t          |t          t          f          rt	          j        d| d| d|          }?|t	          j        d| dd|          }\t	          j        d| dd| d|          }{|S )Nz(:z([^1-9a-zA-Z_]))z\2zNULL\2"z"\2)r@  
isinstanceintfloatresub)rE  rF  resrH  rI  s        rJ  	sql_debugrU  J   s    
C 	F 	F1a#u&& 	F&2q222IIIsCCCCY&2q222JDDCC &2q222KKKKEECCJrL  c                   ~   e Zd ZdZdZg dZdZg dZed             Z	ed             Z
ed             Zed	             Zed
             Zed5d            Zed6d            Zed7d            Zed             Zed             Ze	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d8d            Zed             Zed             Zed             Zedej        j        fd            Zed9d            Ze ed          d:d                        Zed             Ze edddd !          d"                         Z ed#             Z!ed$             Z"e	 	 d;d%            Z#e	 	 d<d&            Z$e	 	 	 	 	 	 d=	 	 	 d>d*            Z%ed+             Z&ed?d0            Z'ed@d3            Z(eed4                         Z)dS )ACmfFullSearchuC   
    Сервис полнотекстового поиска.
    russian)r2  text_renderr0  
text_draftr3  	parent_idtree_parent_id
project_idcmf_created_atcmf_modified_atcodecmf_deletedcmf_archivedloginemailphonephone_internalphone_mobilephone_2phone_assistant
ip_addressemail_2birthdayT)fulltext_searchrun_force_reindexindex_statsc                     t          |d                              d                              d                                          S )Nzhtml.parser
ignore)errors)r   get_textencodedecode)clstext_with_htmls     rJ  
strip_htmlzCmfFullSearch.strip_html   s>    ^];;DDTJJQQYaQbbiikkkrL  c                     ddt                    k     rgS fdt          dt                              D             }|S )Ni d   c                 0    g | ]}||z   z            S  r}  ).0r   overlapr0  text_len_maxs     rJ  
<listcomp>z6CmfFullSearch._split_size_to_parts.<locals>.<listcomp>   s,    YYY!tAanW,,-YYYrL  r   )lenrange)rw  r0  rT  r  r  s    ` @@rJ  _split_size_to_partsz"CmfFullSearch._split_size_to_parts   s_     t99|##6MYYYYYYuQD		<7X7XYYY
rL  c                 f    d                     d t          j        d|          D                       S )N c                 <    g | ]}|t          |          d k     |S )2   )r  r~  ws     rJ  r  z+CmfFullSearch._strip_50.<locals>.<listcomp>   s(    OOOqQO3q66B;;;;;rL  z\sjoinrR  splitrw  r0  s     rJ  	_strip_50zCmfFullSearch._strip_50   s/    xxOOBHUD$9$9OOOPPPrL  c                 f    d                     d t          j        d|          D                       S )Nr  c                 H    g | ]}|                                 t          v| S r}  )lowerALL_STOP_WORDSr  s     rJ  r  z1CmfFullSearch._strip_not_word.<locals>.<listcomp>   s+    nnnqaggii_mNmNmNmNmNmrL  z[ \s<>|&\/%@!`+=;.]r  r  s     rJ  _strip_not_wordzCmfFullSearch._strip_not_word   s2     xxnnBH-CT$J$JnnnooorL  c                     dd l }d}d| d| }| j        j                                                            |                    d          d|i                                          }|S )Nr   zCmfFullSearchLock:_zKSELECT pg_try_advisory_xact_lock(('x' || md5(:lock_key))::bit(64)::bigint);lock_key)
sqlalchemydp_ddSessionexecuter0  scalar)rw  obj_idsapart_nor  rT  s         rJ  _fullsearch_obj_lock_get_pgz)CmfFullSearch._fullsearch_obj_lock_get_pg   s    :::::fj  ""**277  4A  ,B  ,BD
  688 	 
rL  F c                    t          j                     }t                              d|            d|z   }|st          d          dd l}| j        j        }|                    |           }|j        }|	                                }	| 
                    |          }
|
s t                              d| d           d S d}|                    |j        j        g                              |j        j        |k                                  |j        j        |k                                              }|	                    |                                          }|r|d         }|                                                    |j        j        |k                                  d|j                                                  }|	                    |           nt                              d	|            |                                 }|                                                    ||d|j                                        ||
          }|	                    |           |r%ddlm}  |t8          j        j        d|id           t          j                     |z
  dk    r3t                              dt          j                     |z
              d S d S )Nzcmf_full_search: mark_dirty zDEBUG_MSG: empty obj_idr   )cmf_full_search: _text_search_sql_insert  lockedT)is_dirtydirty_atz#cmf_full_search: mark_dirty insert )idr  r  r  r  obj_name)schedule_deferred_jobr     )kwargs	countdowng?zPROF mark_dirty() got )timegdebug
ValueErrorr  r  data_driverdp_model_cls	__table__r  r  selectcr  r   r  r  with_for_updater  firstupdatevaluesfuncr  gen_idinsertcmf.includer  models	CmfPersoncelery_full_search_index)rw  r  
fast_index	debug_msgprof_str  ddsa_modeltabler  rT  r  get_stmtget_resid_update_stmtinsert_stmtr  s                     rJ  mark_dirty_deferzCmfFullSearch.mark_dirty_defer   s   )++	7v77888!I-	 	._---V??3''"JJLL--f55 	GGOOOOPPPFIIuwzl##uw~/00uw'122 ""	 	 ))H%%++-- 	#!*CU57:,--V!W[[]]     IIk""""GGB&BBCCC**,,CV!!W[[]]#&     IIk""" 	u999999!!&"2"KU]_eTfrstttt9;; 4''GGDTY[[7-BDDEEEEE ('rL  c                    |r|                      ||          S t          j                            |          }|r|d         dk    rd}||dt          j        |<   t	          t          j                  dk    rt          d           d S d S )N)r  r  Tr  r  i'  u   DEV: WARNING! Большое количество блокировок может падать на некоторых инсталяциях)r  r  deferred_fullsearch_dirty_listgetr  	cmf_alert)rw  r  r  forcer  prevs         rJ  
mark_dirtyzCmfFullSearch.mark_dirty   s      	G'':'FFF/33F;; 	D&,,JBL[d3e3e(0q/00E99  f  g  g  g  g  g :9rL  c                    |ri t           _        d S t           j        sd S t           j        }t          |          dk    rt          dt          |                      t	          |                                          D ]H}||         }|                     ||                    d          |                    d                     Ii t           _        d S )Nr  ua   DEV: CmfFullSearch помечено грязными слишком много объектов: r  r  r  )r  r  r  r  sortedkeysr  r  )rw  
only_clean
dirty_listr  r  s        rJ  apply_deferred_dirtyz"CmfFullSearch.apply_deferred_dirty   s     	/1A,F/ 	F5
z??R  Lz}  I  {J  {J  L  L  M  M  MZ__..// 	q 	qF'F  FJJ|4L4LX^XbXbcnXoXo pppp+-(((rL  c                    |st          d          dd l}| j        j        }|                    |           }|j        }|                                }|                    |j        j	        g          
                    |j        j        |k              
                    |j        j        dk                                              }|                    |                                          }|r|d         }	|                                
                    |j        j	        |	k                                  dd|j                                                  }
|                    |
           | j                                         d S )Nr  r   F)r  is_dirty_patchr  )r  r  r  r  r  r  r  r  r  r  r   r  r  r  r  r  r  r  r  r  commitrw  r  r  r  r  r  r  r  r  r  r  s              rJ  
mark_cleanzCmfFullSearch.mark_clean
  sK    	._---V??3''"JJLL IIuwzl##uw~/00uw!+,, ""	 	 ))H%%++-- 	#!*CU57:,--V"#(W[[]]     IIk"""rL  c                 :   |st          d          dd l}| j        j        }|                    |           }|j        }|                                }|                    |j        j	        g          
                    |j        j        |k              
                    |j        j        dk                                              }|                    |                                          }|r|d         }	|                                
                    |j        j	        |	k                                  |j                                        t)          j        d          z             }
|                    |
           | j                                         d S )Nr  r      )hours)delay_error_reindex)r  r  r  r  r  r  r  r  r  r  r   r  r  r  r  r  r  r  r  r  datetime	timedeltar  r  s              rJ  mark_delay_error_reindexz&CmfFullSearch.mark_delay_error_reindex)  sY    	._---V??3''"JJLL IIuwzl##uw~/00uw!+,, ""	 	 ))H%%++-- 		#!*CU57:,--V(*8JQR8S8S8S(S     IIk"""rL  N0_full_indexc&                    |dk    r0|                      |           | j                                         d S |                     |          d d         }|}&d}'|r|'|z  }'|	r|'d|	z   z  }'|
r|'d|
z   z  }'|!r|'d|!z   z  }'|&d|!z   z  }&|                     |'          }(|                     |(          }(|dk    rk|rI|                     |          })|                     |)          }*|*d          })|                     |)          }+n#|d d          })|)g}*|                     |)          }+|r-|}|                     |          },|                     |,          },nd }d },|r5|                     |          }|d d         }|                     |          }-nd }d }-|r5|                     |          }.|.d d         }.|                     |.          }/nd }.d }/|rBt          |          }0|                     |0          d d         }0|                     |0          }1nd }0d }1|!r|!}!|!}2n&d }!d }2n!|d	k    rd g}*d }+d }d },d }d }-d }.d }/d }0d }1d }!d }2d })d}3|r|}3|!r|!d d         dz   |3z   }3d}4|rI|4d                    d
 t          |	                                          D                       d d         z  }4|r|4d|d d         z   z  }4|4d|z   z  }4|                     |3          }3|                     |4          }4|                     |3          }5|                     |4          }6|5
                    d          }7|6
                    d          }8|7|8z   }9|9dk     rn>|9dz
  }:|7dk    r|8dk    r_d                    |5                                d d                   }5d                    |6                                d d                   }6nd                    |5                                d d|8z
                     }5|6}6n|7dk     r5|5}5d                    |6                                d d|7z
                     }6n^d                    |5                                d d                   }5d                    |6                                d d                   }6|dz   |3z   dz   |4z   };|;d d         };|;                                };|                     |;          }< | j        d<i ddd|d|d|d|d|d|d|d|d|d|d|d|d|d|d |d!|d"|d#|d$|d%|)d&|+d'|&d(|(d)|d*|,d+|d,|-d-|;d.|<d/|.d0|/d1|0d2|1d3| d4|!d5|2d6|"d7|#d8|$d9|% t          |*          d:k    rt          |*d:d          d:          D ]\  }=}>|> })|                     |)          }+ | j        d<i d|=d|d|d|d|d|d|d|d|d|d|d|d|d|d|d |d!|d"|d#|d$|d%|)d&|+d-d d.d d'|&d(d d)d d*d d+d d,d d/d d0d d1|0d2|1d3| d4d d5d d6|"d7|#d8|$d9|% |                     |t          |*          ;           | j                                         d S )=N	9_disablei  r  r  z DZQTN r  r   i 1_namec              3      K   | ]}|V  d S Nr}  )r~  rI  s     rJ  	<genexpr>z-CmfFullSearch.index_object.<locals>.<genexpr>  s"      *Z*Z1*Z*Z*Z*Z*Z*ZrL  i  u
    Тэги i>  i  i*  i:  r  r  	obj_modelobj_parent_idobj_tree_parent_idobj_project_idobj_company_idobj_created_atobj_modified_atobj_codeobj_deletedobj_archivedobj_owner_nameobj_author_nameobj_modified_by_nameobj_responsible_namesobj_hrefobj_logic_type_codeobj_activity_codeobj_status_typeobj_texttext_for_vecr  name_for_vecobj_tagstags_for_vecobj_result_textresult_text_for_vecobj_ml_textml_text_for_vecobj_commentscomments_for_vecobj_addon_fieldsobj_addon_fields_for_vecobj_user_ratingobj_key_phraseskey_phrases_for_vecobj_breadcrumbsobj_related_person_loginsobj_user_portal_topobj_client_portal_topr  )delete_from_partnor}  )'_text_search_sql_delete_obj_with_childsr  r  r  r  r  rC  r  setr  countr  r  _text_search_sql_insertr  	enumerate_text_search_sql_delete_partno)?rw  
model_namer  r  r2  r0  text_prefixtext_suffixfull_search_typecompany_nameproject_namemodel_verbose_namer  comments_textr  r  r  r  r  r   r  r  r  r  r  r  r  r  r  r  r  obj_addon_fields_dictr  r  r  r  r  r  r  
smart_namer  r  obj_text_listr  r  r  obj_comments_textcomments_text_for_vecr  r  r  obj_ml_text_mainobj_ml_text_suffixml_text_main_for_vecml_text_suffix_for_vecmain_token_lensuffix_token_lentotal_token_lenoversize_lenr	  r
  r  obj_text_parts?                                                                  rJ  index_objectzCmfFullSearch.index_objectF  s
   T {**77???FMMOOOF mmK00$7 
 	$J 	-#,,J 	-#,,J 	4#//J	O33H**:66}}\22~-- ===.. # 8 8 B B ,A.0"228<<)%4%02!)
"228<< $#"228<<"}}\::# +"%--"@"@"1'6'":&)&9&9/&J&J##"&&*# -$'MM-$@$@!$5gvg$>!(+(;(;<M(N(N%%$(!(,%$ 0#&'<#=#= #&==1A#B#B7F7#K +.+>+>?O+P+P((#' +/( +"1&5## #'&*##))!FMLHL"O"& $$(!#'+$"O"&H  	$# 	O.uu5;>NN  	b#((*Z*Zc:O:V:V:X:X6Y6Y*Z*Z*Z"Z"Z[`\`[`"aa 	A,%4%"@@cM11==)9:: ]]+=>>"223CDD!$!4!45G!H!H-33C88177<<(+;; V##  +V3L&&#u,,+.884H4N4N4P4PQXRXQX4Y+Z+Z(-0XX6L6R6R6T6TU[V[U[6\-]-]**+.884H4N4N4P4PQqR`aqRqQq4r+s+s(-C**&((';$),2H2N2N2P2PQoR`aoRoQo2p)q)q&& (+xx0D0J0J0L0LWfW0U'V'V$),2H2N2N2P2PQWRWQW2X)Y)Y& "C'*::S@CUU!'6'* "''))--k:: 	$# 	
 	
 	
AA 	
ff 	


 	
'-	
<N<N	
_m_m	
 M  M	
)>	
;J?	
 X	
 ,7;	
 FR\	
 cqbp	
 ,O		
 CWBV		

 #8"7	

 CK(	
 !4 3	
 HYGX	
 kzjy	
 X	
 -9L	
 X	
 -9L	
 X	
 -9L	
 ,O	
 BUAT	
 $	
 6E_	
 +*	
 >S=R	
 .-	
 IaH`	
 ,O	
  ,O!	
  BUAT!	
" ,O#	
$ '@&?%	
& !4 3'	
( #8"7)	
 	
, }!!*3M!""4Eq*I*I  & ,-"228<<++   GG FF V`V` "/-DVDVgugu GU  GU#1>CR? &X 4?; NZ\ kyjx %4O	 K_J^	
 +@*?
 KS( )<(; PaO` sB  sB &X 5AL !% 7;d &X 59D "T 15 %)D ?Cd "& 9= &6%5 QiPh %4O  %)D!  ?Cd!" %4O#$ /H.G%& )<(;'( +@*?)  , 	**6c-FXFX*YYYrL  c                 `   |st          d          dd l}| j        j        }|                    |           }|j        }|                                }|                    |                              |j	        j
        |k    |j	        j        |k    z            }|                    |           d S Nr  r   )r  r  r  r  r  r  r  deleter   r  r  r  r  )rw  r  r  r  r  r  r  del_stmts           rJ  r  z5CmfFullSearch._text_search_sql_delete_obj_with_childsG  s      	._---V??3''"JJLL99U##))W"f,W^v%'
 
 	
		(rL  c                    |st          d          dd l}| j        j        }|                    |           }|j        }|                                }|                    |                              |j	        j
        |k                                  |j	        j        |k              }|                    |           d S r5  )r  r  r  r  r  r  r  r6  r   r  r  r  r  )	rw  r  r  r  r  r  r  r  r7  s	            rJ  r  z,CmfFullSearch._text_search_sql_delete_partno[  s     	._--- V??3''"JJLL IIeU57>V+,,U57?&8899 	 	
		(rL  c*           	         t                               d|            |st          d          dd l}*| j        j        }+|+                    |           },|,j        }-|+                                }.| 	                    |          }/|/s t                               d| d           d S |*
                    |-j        j        g                              |-j        j        |k                                  |-j        j        |k                                              }0d }1|r|                    d          d         }1t%          |.                    |0                    }2|2rMt)          |2          dk    rt+          d| d| d	d
           |2d         d         }3 |-                                                    |-j        j        |3k              j        d<i d|ddddd|d|d|d|d|d|d|d|!d|d|1d|d|d|d|d|	d|*j        j                            | j        |          d |*j        j                            | j        |          d!|*j        j                            | j        |          d"|*j        j                            | j        |          d#|*j        j                            | j        |          d$|*j        j                            | j        |           d%|*j        j                            | j        |"          d&|
d'|d(|d)|d*|d+|d,|d-|d.|d/|d0|d1|#d2|$d3|*j        j                            | j        |%          d4|&d5|'d6|*j        j                            | j        |'          d7|(d8|)}4|.                    |4           n(t                               d9|            |                                 }3 |-                                j        d<i d:|3ddddd;|d|d|d|d|d|d|d|d|d|!d|d|1d|d|d|d|d|	d|*j        j                            | j        |          d |*j        j                            | j        |          d!|*j        j                            | j        |          d"|*j        j                            | j        |          d#|*j        j                            | j        |          d$|*j        j                            | j        |           d%|*j        j                            | j        |"          d&|
d'|d(|d)|d*|d+|d,|d-|d.|d/|d0|d1|#d2|$d3|*j        j                            | j        |%          d4|&d5|'d6|*j        j                            | j        |'          d7|(d8|)}5|.                    |5           |3S )=Nr  r  r   r  :r  u   Для объекта z	(part_no=u   ) задублировались записи в поиске. Обратитесь в техническую поддержку!Tabortr  r  Fr  r  r  r  r	  r  r  r  r  r  obj_parent_modelr  r  r  r  r  name_tsvectortext_tsvectorml_text_tsvectortags_tsvectorresult_text_tsvectorcomments_tsvectoraddon_fields_tsvectorr  r  r  r  r  r  r  r  r  r   r  r  r  key_phrases_tsvectorr  r  "obj_related_person_logins_tsvectorr  r  z0cmf_full_search: _text_search_sql_insert insert r  r  r}  )r  r  r  r  r  r  r  r  r  r  r  r  r  r   r  r  r  r  listr  r  r  r  r  rE  r  to_tsvector_fts_configr  r  )6rw  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r  r  r  r	  r
  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  rT  r  r=  r  r  r  r  s6                                                         rJ  r  z%CmfFullSearch._text_search_sql_insertn  s   ( 	
DFDDEEE 	._--- V??3''"JJLL--f55 	GGOOOOPPPF IIuwzl##U57>V+,,U57?g-.._	 	   	;,22377:qyy**++ n	#7||a  O6  O  OG  O  O  O  W[  \  \  \  \!*Q-CuwzS())/ / / "6/ #U	/
 $)5/ (i/ &X/ &X/ !,/ &X/ %4O/ "./ &6%5/ #0-/ &6%5/  (:'9!/" $2>#/$ $2>%/& $2>'/( %4O)/* #%&+"9"9#/<"X"X"X+/, #%&+"9"9#/<"X"X"X-/. &(V[%<%<S_o%^%^%^//0 #%&+"9"9#/<"X"X"X1/2 *,)@)@Re)f)f)f3/4 ')fk&=&=coO_&`&`&`5/6 +-&+*A*A#/Sk*l*l*l7/8 &X9/: !,;/< ".=/> $2>?/@ %4OA/B *>)=C/D +@*?E/F &XG/H )<(;I/J '8&7K/L %4OM/N %4OO/P %4OQ/R *,)@)@Re)f)f)fS/T %4OU/V /H.GW/X 8:v{7N7Ns`y7z7z7zY/Z )<(;[/\ +@*?]/ d IIk""""GGOvOOPPP**,,C0 0 0s0 #U0 $)5	0
 $G0 "60 (i0 &X0 &X0 !,0 &X0 %4O0 ".0 &6%50 #0-0  &6%5!0" (:'9#0$ $2>%0& $2>'0( $2>)0* %4O+0, #%&+"9"9#/<"X"X"X-0. #%&+"9"9#/<"X"X"X/00 &(V[%<%<S_o%^%^%^102 #%&+"9"9#/<"X"X"X304 *,)@)@Re)f)f)f506 ')fk&=&=coO_&`&`&`708 +-&+*A*A#/Sk*l*l*l90: &X;0< !,=0> ".?0@ $2>A0B %4OC0D *>)=E0F +@*?G0H &XI0J )<(;K0L '8&7M0N %4OO0P %4OQ0R %4OS0T *,)@)@Re)f)f)fU0V %4OW0X /H.GY0Z 8:v{7N7Ns`y7z7z7z[0\ )<(;]0^ +@*?_0 f IIk"""
rL  objc                 l    |j         sd S | j        D ]"}|dk    r	||j        v r||         j        r dS #d S )Nr_  T)full_searchrequired_fieldsr
   
is_changed)rw  rJ  
field_names      rJ  is_obj_need_reindexz!CmfFullSearch.is_obj_need_reindex  s_     	F - 	 	J...SZ''C
O,F'tt		 	rL  r{  c           
         t           j        j                                        D ]$}|j        s|j        }|r||vrd}t                              |          }|j        }|rdg}	 t          j	                    }	|
                    ||||z   gdgdd          }
|
sn|
D ]D}|r,t          j                            |j        j        d           0|                                 E|t!          |
          z  }| j                                         t&                              d| d| d	t          j	                    |	z
  d
d           &d S )Nr   r  Tr^  )r
   sliceorder_byinclude_archivedinclude_deleted)r  zCmfFullSearch.reindex_models: r:  z, z0.3z sec)cmfr  	CmfEntityiter_subclassesrL  
class_namecmfutilget_model_by_namefull_search_preload_fieldsr  rG  rW  r  r  r:  full_search_indexr  r  r  r  r  )rw  models_listcommit_everylazy	model_clsr  offsetmodel
field_listtsobj_listrJ  s               rJ  reindex_modelszCmfFullSearch.reindex_models  s   -==?? 	l 	lI( "-J z<<F--j99E9J $"V
lY[[ ::%!6,#67./%)$( &     # 0 0C 0,77D7QQQQ--////#h--'jjjfjjPTPYP[P[^`P`jjjjkkk'l +	l 	lrL  )	only_oncec                 N   | r|st          dd           t                              d           t          j                                         t          j        }|j        j        }|	                    |          }|j
        }|                                }d}| rd}t          d| dd	d
           	 d| d| d}|                    |          }	t          |	          }	|                                 t!          |	          rt          dd	d
           nt                       d S t)Nu   Поиск после обновления должен работать сразу, с приемлемым качеством без переиндексацииTr;  zRun run_force_reindexr  r  zrun_force_reindex Process z=true: r  )endflushz
                WITH cte AS (
                SELECT
                    id as id
                FROM   cmf_full_search
                WHERE  z=false AND part_no=0
                ORDER BY dirty_at DESC
                LIMIT  1000
                )
                UPDATE cmf_full_search s
                SET
                    zt = true
                FROM   cte
                WHERE  cte.id = s.id
                RETURNING s.id;
            .)r  r  r  r  CmfAccessListcheck_admin_moderW  r  r  r  r  r  printr  rG  r  r  )

from_patchi_do_manual_migrationrw  r  r  r  r  dirty_fieldrE  rT  s
             rJ  rn  zCmfFullSearch.run_force_reindex>  sf     	J3 	J   }  EI  J  J  J  J	()))--///"V??3''"JJLL ! 	+*K?;???RtTTTT	
 $  !  C  ))C..Cs))CHHJJJ3xx cr.....1	rL  c                     t           j                                         |                                 }|                     d          }||dS )NT)r  )totaldirty_count)r  rm  rn  r  )rw  rt  ru  s      rJ  ro  zCmfFullSearch.index_stats~  sN    --///		iii.. &
 
 	
rL  z	@minutely   )rh  
system_jobschedulepriorityc                  	   t                               d           t          j                                        rt                               d           d S t          j        d           t          j                    } d}g }	 t          j        	                    dgg ddg d	g d
gdddt          j
                                        t          j        d          z
  gg dgdddt          j
                                        gg dggdgddg          }|sn:i }|D ]J}t                              |j                  }||vrg ||<   ||                             |j                   K|                                D ]\  }}t                               d| dt#          |                      t%          |           |D ]}|                    |j        dd|gd          }	|dz  }|	st          j                            |g d          }
d|
j         d|
j         d|
j         d |
j         d!|
j         
}t                               |t2          j        "           t          j                            |           t                               d#|	j                    	 |	                                 # t:          $ r}t                               d$| d|	 d%| t2          j        "           t                               t=          j                               |                    ||g           tA                       t          j        !                    |           tE                       Y d }~d }~ww xY wt          j                    | z
  d&k    r|t          j
                                        #                                j$        }|dk    r"|dk     rt          j                    | z
  d'k    rnbnt                               d(| d)           nBtE                       t                               d*| d+           t          j        d           |r[t                               d,t2          j        "           |D ]$\  }}t                               | d-|            %|d         d         t                               d.t          j                    | z
              d S )/NzStart cron_index_dirtyuJ   Не индексируем поскольку запущен импорт   r   Tr  )r  =r   OR)r  r|  T)r  r|  Tr  <   )minutes)r  r|  Nr  )r  r|  Nz	-dirty_at   )r
   filterrS  rR  zcron_index_dirty process r  r  r|  )r
   r  rU  r  )r  r  r  r  r  )r  r
   u   cron_index_dirty: Не индексируем поскольку объект не найден или удален в бд fullsearch id:z
 obj name:z	 obj id: z
 dirty_at:z
 is_dirty:)levelzobj_id=u#   ERROR! При индексации u"    произошла ошибка:    -   ua   cron_index_dirty превышен лимит времени 20 секунд обработано u    объектовu&   cron_index_dirty обработано u    объектов, sleep 1u2   При индексации были ошибки:z: zEnd cron_index_dirty at )%r  r  rZ  enable_import_modeimport_is_runningr  sleepr  rW  slistr  r  r  get_model_by_idr  appendr@  r  ro  r  r\  r  r  r  r  loggingERRORr  r]  	Exception	traceback
format_exccmf_rollbackr  
cmf_commit
astimezonehour)stn
exceptionsobj_id_listobj_ids_by_modelr  rc  id_listr  rJ  
search_rawerr_strer  s                 rJ  cron_index_dirtyzCmfFullSearch.cron_index_dirty  s    	
()))%7799 	GG`aaaF
1Y[[
F	 .44XJ*=*=*=+/1H1H1HJgJgJg*h+/-7h>O>S>S>U>UX`XjstXuXuXu>u,v,C,C,C+,
 *.-BCIZI^I^I`I`,a,N,N,N)*.(" 1<}-.G' 5 5 5K(  !% > >//>> 000.0$U+ '..v}===="2"8"8":": % %wJEJJCLLJJKKKg" % %C))5+KUY[^`cTdvz){{CFA 	!%+%9%=%=S  RF  RF  RF%=  &G  &G
#B1;#B #BJTJ]#B #Bhrhy#B #B FP  FY#B #B,6,?#B #B w}===,TTUXYYY GG.cf..///%--////$ % % % vc v vC v vst v v  F  L  M  M  M	 4 6 6777"))3(333$,EEcJJJ"%!%0 y{{R"$$(,,..99;;@199 y{{R'",, - GG  U  AB  U  U  U  V  V  VLLLGGZQZZZ[[[JqMMMMF	P  	#GGIQXQ^G___$ ' 'Q3!&&&&Q-""	;49;;r>;;<<<<<s   J33
M4=B,M//M4c                 B    t          j        j        j        j        |i |S r  )rV  r  cmf_search_engineCmfSearchEngine
fts_search)rw  argsr  s      rJ  rm  zCmfFullSearch.fulltext_search  s!    z+;FWPVWWWrL  c                  R    t           j        j        j                                        S r  )rV  r  r  r  &gevent_bm25_stat_words_load_with_delayr}  rL  rJ  r  z4CmfFullSearch.gevent_bm25_stat_words_load_with_delay  s    z+;bbdddrL  c
                     g S r  )rO  rR  addon_filterr  archiveddeletedtree_parent_filterformatr  _build_tags_filtertag_name#_build_related_person_logins_filterALLOWED_FIELDSr  rP  r  rW  r  r  r  r  rR  rS  tuplequery_qstop_words
query_likequery_obj_coderG  )*rw  model_name_intsquery_strforce_field_nameage_dayslabelforce_sliceinclude_attachmentsearchmarkrO  rR  r[  modified_by_nameresponsible_namelogic_type_codestatus_typemodified_at_beforemodified_at_afterr  r  user_rating
owner_nameauthor_namer  include_attachment_filtertags_filtertags_params
rpl_filter
rpl_paramssearch_fieldheadline_fieldtsvector_field
slice_from	slice_forage_days_subquery
max_partnotsquery_str_h1tsquery_str_h2ts_rank_normalizerE  
found_objss*                                             rJ  search_oncezCmfFullSearch.search_once  s	     rL  c
                 D	   |p|	j         }
|
t          vrt          d|
 d           d|
 }d|
 }|
dk    s|
dk    rd}|
 d}d	 } |||          \  }}}d
}d
}d
}d
}d
}d
}|rd| d}d| d}|rd| d}d| d}|rd| d}d| d}d}|	j        r:t	          |	j                            d                    dk    r|dk    rd}nd| d}|r|}n|	j        }|	j                            dd           }|	j                            d          }|	j                            dd           }|	j                            dd           }|	j                            d d           }|	j                            d!          }|	j                            d"          } |	j	        }!|	j
        }"|	j                            d#          }#|	j                            d$d           }$|	j                            d%|$          }%|$p|%}$|	j        }&|&r(d&                    d'                    |&                    nd}&|                     |	j                  \  }'}(|r|                     |          \  })}*nO|	j                            d(          r1|                     |	j                            d(                    \  })}*nd})i }*|d)         }+|d*         |d)         z
  },d}-|rt#          |          }d+| d,}-d)}.|
d-k    rd.}.t%          t'          j        d/d|                                                    }/d0                    |/t%          t*                    z
            }0d0                    |/t%          t*                    z
            }1|0}2|1}3d
}4d }5|	j        r,d0                    |	j                                                  }5 d1j        dDi |&|||-||'|4|)|||||||d2}6i d3|	j        d4|d5|	j        d6|0d7|1d8|2d9|3d:|+d;|,d<t3          |          d=|d>|5pd d?|	j        pd d@|	j        pd dA|	j        dB|.d||$|%|||||| |!|"|#|||dC|(|*}7t8          j        j        j                                         !                    |6|7          "                                }8tG          |8          S )EN6   Недопустимое значение field_name: Tr;  obj_r2  r1  r  	_tsvectorc                 *   g }g }g }d}|dgk    rd}t          t          d          rt          j        st          t	          j        dd|                                                     D ]}|                    |           d                    |          d                    |          d                    |          fS t          j        d         |         }t          j        d	         |         }t          t	          j        dd|                                                     D ]}|t          j        vs|t          j        |         vr|                    |           :t          j        |         |         |k    r|                    |           lt          j        |         |         |k    r|                    |           |                    |           d                    |          d                    |          d                    |          fS )
NdiCmfTasktiFTS_STAT_WORDS[()!|&']r   | FST_FRQ_MIDFST_FRQ_LOW)	hasattrAPPr  r  rR  rS  r  r  r  )	tsqueryr  
query_high	query_mid	query_lowselectortokenfrq_midfrq_lows	            rJ  tsquery2idfqueryz<CmfFullSearch.search_once_top_bm25.<locals>.tsquery2idfquery  s   JIIH++3 011 *9K * 
3!@!@!F!F!H!HII , ,E$$U++++zz*--JJy))JJy))* *
 (7AG(7AGRVJsG<<BBDDEE - - 222hcFXY^F_6_6_$$U++++'.x87BB$$U++++'.x87BB$$U++++%%e,,,,::j))JJy))JJy))* *rL  0z&ts_rank(setweight(name_tsvector,'C')||z, :query_high)zts_rank(setweight(z,'C'), :query_high)z&ts_rank(setweight(name_tsvector,'B')||z, :query_mid)z,'B'), :query_mid)z&ts_rank(setweight(name_tsvector,'A')||z, :query_low)z,'A'), :query_low)r  r     r	  z\ or (obj_ml_text LIKE '%' || :query_like || '%' or obj_text LIKE '%' || :query_like || '%') z or z  LIKE '%' || :query_like || '%' r[  r  r  r  r  r  r  r  r  r   AND obj_tree_parent_id IN ('{}')','related_person_loginr   r  $obj_modified_at > now() - interval '
 days' ANDr0  @B r  r  uD  

            SET gin_fuzzy_search_limit=100000;
            SET default_text_search_config = 'russian';

            SELECT
                subs.*,
                subs.obj_name as title,
                ts_headline(
                    'russian',
                    substring(COALESCE(subs.headline_raw, subs.obj_name) FROM 0 FOR 100000),
                    plainto_tsquery(:param_search_query),
                    'MaxFragments=1,MaxWords=25,MinWords=24'
                ) AS headline
            FROM (
                (
                    SELECT
                        obj_id,
                        obj_code,
                        {headline_field} as headline_raw,
                        obj_model,
                        --obj_name || ' - ' || rank as title,
                        obj_breadcrumbs as breadcrumbs,
                        obj_project_id as obj_project_id,
                        obj_parent_id as obj_parent_id,
                        obj_related_person_logins as obj_related_person_logins,
                        :label || (CASE WHEN EXTRACT(days from (now()-obj_modified_at)) < 3*365 then 'R' else '' end) as label,
                        --- Множители сбросили на 1 тк выше уже есть умножение через A B C D но можно убрать A B C D Сделать только С а множители расставить уже здесь
                        {txt_tsrank_high_string} + {txt_tsrank_mid_string} * 1 + {txt_tsrank_low_string} * 1 as rank,
                        EXTRACT(days from (now()-obj_modified_at)) as age_days,
                        {tsvector_field} as result_tsvector, {search_field} as result_text, name_tsvector, obj_name, obj_modified_at,
                        obj_user_portal_top, obj_client_portal_top,
                        'flow_main' as mark
                    FROM cmf_full_search
                    WHERE
                        -- obj_code='DOC-006092' and
                        {age_days_subquery}
                        ({search_field} != '' and {search_field} is not null) and
                        (
                           ( {tsvector_field} @@ :txt_tsquery_str_where_OR
--ниже спорная строка часть данных может не найтись сложная проблема релевантности текста и имени
                             and ts_rank({tsvector_field}, :txt_tsquery_str_rank_OR) > 0.0001
                           )
                         OR
                           (:query_like is not null and  {search_field} LIKE '%' || :query_like || '%')
                         )

                        -- Это делаем, чтобы исключить отсюда результаты из top1
                        -- но это может привести к тому, что по top1 ранк низкий а здесь высокий, но мы его исключили
                        -- and not(name_tsvector @@ :tsquery_str_where_OR)

                        and ((obj_model IN :model_name_in))
                        and (:query_qstop_words_str is null or not(text_tsvector @@ :query_qstop_words_str))
                        and part_no <= :max_partno
                        and ( :parent_id is null or obj_project_id = :parent_id )
                        AND ( :owner_name IS NULL OR obj_owner_name = :owner_name )
                        AND ( :author_name IS NULL OR obj_author_name = :author_name )
                        AND ( :modified_by_name IS NULL OR obj_modified_by_name = :modified_by_name)
                        and ( :responsible_name is null or obj_responsible_names ILIKE '%' || :responsible_name || '%' )
                        {tags_filter}
                        {rpl_filter}
                        {tree_parent_filter}
                        and ( :logic_type_code is null or obj_logic_type_code = :logic_type_code )
                        and ( :status_type is null or obj_status_type = :status_type )
                        AND ( :modified_at_before IS NULL OR obj_modified_at <= :modified_at_before )
                        AND ( :modified_at_after IS NULL OR obj_modified_at >= :modified_at_after )
                        and ( :archived is null or obj_archived = :archived )
                        AND ( :deleted IS NULL OR obj_deleted = :deleted )
                        and ( :user_rating is null or obj_user_rating >= :user_rating)
                        and 1=1
                    ORDER BY rank desc
                    LIMIT :slice_for OFFSET :slice_from
                )
            UNION ALL
                (
                    SELECT
                        obj_id,
                        obj_code,
                        COALESCE({headline_field}, obj_name) as headline_raw,
                        obj_model,
                        --obj_name || ' - ' || rank as title,
                        obj_breadcrumbs as breadcrumbs,
                        obj_project_id as obj_project_id,
                        obj_parent_id as obj_parent_id,
                        obj_related_person_logins as obj_related_person_logins,
                        :label || (CASE WHEN EXTRACT(days from (now()-obj_modified_at)) < 3*365 then 'R' else '' end) as label,
                        --- Множители сбросили на 1 тк выше уже есть умножение через A B C D но можно убрать A B C D Сделать только С а множители расставить уже здесь
                        {txt_tsrank_high_string} + {txt_tsrank_mid_string} * 1 + {txt_tsrank_low_string} * 1 as rank,
                        EXTRACT(days from (now()-obj_modified_at)) as age_days,
                        ml_text_tsvector as result_tsvector, obj_text as result_text, name_tsvector, obj_name, obj_modified_at,
                        obj_user_portal_top, obj_client_portal_top,
                        'flow_attach' as mark
                    FROM cmf_full_search
                    WHERE
                        {age_days_subquery}
                        (obj_ml_text != '' and obj_ml_text is not null)
                        and (obj_parent_model != 'CmfPerson')
                        and (
                            ( ml_text_tsvector @@ :txt_tsquery_str_where_OR
--ниже спорная строка часть данных может не найтись сложная проблема релевантности текста и имени
                             and ts_rank(ml_text_tsvector, :txt_tsquery_str_rank_OR) > 0.0001
                            )
                            OR (:query_like is not null and  obj_text LIKE '%' || :query_like || '%')
                            OR (:query_like is not null and  obj_name LIKE '%' || :query_like || '%')
                            OR (:query_like is not null and  obj_ml_text LIKE '%' || :query_like || '%')


                         )

                        and ('{tsvector_field}' = 'ml_text_tsvector')
                        -- Это делаем, чтобы исключить отсюда результаты из top1
                        -- но это может привести к тому, что по top1 ранк низкий а здесь высокий, но мы его исключили
                        -- and not(name_tsvector @@ :tsquery_str_where_OR)

                        and (obj_parent_model IN :model_name_in and obj_model = 'CmfAttachment')
                        and (:query_qstop_words_str is null or not(ml_text_tsvector @@ :query_qstop_words_str))
                        and part_no <= :max_partno
                        and ( :parent_id is null or obj_project_id = :parent_id )
                        AND ( :owner_name IS NULL OR obj_owner_name = :owner_name )
                        AND ( :author_name IS NULL OR obj_author_name = :author_name )
                        AND ( :modified_by_name IS NULL OR obj_modified_by_name = :modified_by_name)
                        and ( :responsible_name is null or obj_responsible_names ILIKE '%' || :responsible_name || '%' )
                        {tags_filter}
                        {rpl_filter}
                        {tree_parent_filter}
                        and ( :logic_type_code is null or obj_logic_type_code = :logic_type_code )
                        and ( :status_type is null or obj_status_type = :status_type )
                        AND ( :modified_at_before IS NULL OR obj_modified_at <= :modified_at_before )
                        AND ( :modified_at_after IS NULL OR obj_modified_at >= :modified_at_after )
                        and ( :archived is null or obj_archived = :archived )
                        AND ( :deleted IS NULL OR obj_deleted = :deleted )
                        and ( :user_rating is null or obj_user_rating >= :user_rating)
                        and 1=1
                    ORDER BY rank desc
                    LIMIT 20 OFFSET :slice_from/:slice_for*4
                )
            UNION ALL

                (
                    SELECT
                        obj_id,
                        obj_code,
                        ts_rank(setweight(name_tsvector,'C') || {tsvector_field}, :tsquery_str_rank_OR)|| obj_name ||' '|| {headline_field} as headline_raw,
                        obj_model,
                        --obj_name as title,
                        obj_breadcrumbs as breadcrumbs,
                        obj_project_id as obj_project_id,
                        obj_parent_id as obj_parent_id,
                        obj_related_person_logins as obj_related_person_logins,
                        :label || (CASE WHEN EXTRACT(days from (now()-obj_modified_at)) < 3*365 then 'R' else '' end) as label,
                        -- (ts_rank(setweight(name_tsvector,'C') || ml_text_tsvector, :tsquery_str_rank_OR, {ts_rank_normalize}))
                        -- * (CASE WHEN EXTRACT(days from (now()-obj_modified_at)) < 3*365 then
                        --             ((3*365-EXTRACT(days from (now()-obj_modified_at)))/30/100+1)
                        --   else 1 end) as rank,
                        --- Множители сбросили на 1 тк выше уже есть умножение через A B C D но можно убрать A B C D Сделать только С а множители расставить уже здесь
                        {tsrank_high_string} + {tsrank_mid_string} * 1 + {tsrank_low_string} * 1 as rank,
                        EXTRACT(days from (now()-obj_modified_at)) as age_days,
                        COALESCE({tsvector_field}, name_tsvector) as result_tsvector, {search_field} as result_text, name_tsvector, obj_name, obj_modified_at,
                        obj_user_portal_top, obj_client_portal_top,
                        'flow_name' as mark
                    FROM cmf_full_search
                    WHERE
                        {age_days_subquery}
                        ({search_field} != '' and {search_field} is not null) and
                        (
                           (
                             name_tsvector @@ :tsquery_str_where_OR
                             and ts_rank(setweight(name_tsvector,'C') || {tsvector_field}, :tsquery_str_rank_OR) > 0.0001
                           )
                         OR
                           (:query_like is not null and {search_field} LIKE '%' || :query_like || '%')
                         -- <% медленная и на ml_text запускать не вариант 10сек
                         -- experimental
                         OR (:search_query_wo_qstop  <<% obj_name)
                        )
                        and (obj_model IN :model_name_in)
                        and (:query_qstop_words_str is null or not(text_tsvector @@ :query_qstop_words_str))
                        and part_no <= :max_partno
                        and ( :parent_id is null or obj_project_id = :parent_id )
                        AND ( :owner_name IS NULL OR obj_owner_name = :owner_name )
                        AND ( :author_name IS NULL OR obj_author_name = :author_name )
                        AND ( :modified_by_name IS NULL OR obj_modified_by_name = :modified_by_name)
                        and ( :responsible_name is null or obj_responsible_names ILIKE '%' || :responsible_name || '%' )
                        {tags_filter}
                        {rpl_filter}
                        {tree_parent_filter}
                        and ( :logic_type_code is null or obj_logic_type_code = :logic_type_code )
                        and ( :status_type is null or obj_status_type = :status_type )
                        AND ( :modified_at_before IS NULL OR obj_modified_at <= :modified_at_before )
                        AND ( :modified_at_after IS NULL OR obj_modified_at >= :modified_at_after )
                        and ( :archived is null or obj_archived = :archived )
                        AND ( :deleted IS NULL OR obj_deleted = :deleted )
                        and ( :user_rating is null or obj_user_rating >= :user_rating)
                        and 1=1
                    ORDER BY rank desc
                    LIMIT :slice_for OFFSET :slice_from
                )
            UNION ALL








                /* Дополнительно проверяем Полное совпадение CODE или ID или ilike выдаем с высоким рангом 100
                   в теории можно объединить с выше через CASE LIKE или с once_top
                */
                (
                    SELECT
                        obj_id,
                        obj_code,
                        obj_name ||' '|| obj_code || ' ' || obj_id || ' '  || {headline_field} as headline_raw,
                        obj_model,
                        --obj_name,
                        obj_breadcrumbs as breadcrumbs,
                        obj_project_id as obj_project_id,
                        obj_parent_id as obj_parent_id,
                        obj_related_person_logins as obj_related_person_logins,
                        :label || (CASE WHEN EXTRACT(days from (now()-obj_modified_at)) < 365 then 'R' else '' end) as label,
                        1000 as rank,
                        -- 100
                        -- * (CASE WHEN EXTRACT(days from (now()-obj_modified_at)) < 365 then
                        --            (365-EXTRACT(days from (now()-obj_modified_at)))/30+1 else 1 end) as rank,
                        EXTRACT(days from (now()-obj_modified_at)) as age_days,
                        {tsvector_field} as result_tsvector, {search_field} as result_text, name_tsvector, obj_name, obj_modified_at,
                        obj_user_portal_top, obj_client_portal_top,
                        'flow_idcodelike' as mark
                    FROM cmf_full_search
                    WHERE
                        ({search_field} != '' and {search_field} is not null) and
                        /* Дополнительно проверяем полное совпадение CODE ID ML_TEXT >2WORDS по ilike с высоким рангом */
                        (   (:query_obj_code is not null
                                 and (
                                       -- не дает бонуса возможно даже хуже obj_code = :query_obj_code or
                                      obj_code LIKE '%' || :query_obj_code )
                            )
                            or (:query_obj_id is not null and obj_id = :query_obj_id)
                            {idcodelike_like_string}
                        )
                        and (:query_qstop_words_str is null or not({tsvector_field} @@ :query_qstop_words_str))
                        and obj_model IN :model_name_in
                        and part_no <= :max_partno
                        and ( :parent_id is null or obj_project_id = :parent_id )
                        AND ( :owner_name IS NULL OR obj_owner_name = :owner_name )
                        AND ( :author_name IS NULL OR obj_author_name = :author_name )
                        AND ( :modified_by_name IS NULL OR obj_modified_by_name = :modified_by_name)
                        and ( :responsible_name is null or obj_responsible_names ILIKE '%' || :responsible_name || '%' )
                        {tags_filter}
                        {rpl_filter}
                        {tree_parent_filter}
                        and ( :logic_type_code is null or obj_logic_type_code = :logic_type_code )
                        and ( :status_type is null or obj_status_type = :status_type )
                        AND ( :modified_at_before IS NULL OR obj_modified_at <= :modified_at_before )
                        AND ( :modified_at_after IS NULL OR obj_modified_at >= :modified_at_after )
                        and ( :archived is null or obj_archived = :archived )
                        AND ( :deleted IS NULL OR obj_deleted = :deleted )
                        and 1=1
                    /*ORDER BY obj_id desc -- не будем делать, т.к. тормозить будет*/
                    -- хак 50 здесь предполагает что запросы делаются по 50 и будем давать больше лайкответов на след слайсах
                    LIMIT 2+:slice_from/25
                )
            ) as subs
        )r  r  r  r  r  r  r  r  tsrank_high_stringtsrank_mid_stringtsrank_low_stringtxt_tsrank_high_stringtxt_tsrank_mid_stringtxt_tsrank_low_stringidcodelike_like_stringparam_search_queryparam_querysearch_query_wo_qstoptsquery_str_rank_ORtsquery_str_where_ORtxt_tsquery_str_rank_ORtxt_tsquery_str_where_ORr  r  r  r  query_qstop_words_strr  query_obj_idr  r  )r  r  r  r  r  r  r  r  r  r  r  r  r  r  r}  )$rO  r  r  r  r  r  rR  r  r  r  r  r  r  r  r  r  r  rP  r  rR  rS  EVA_OR_QUERY_STOP_WORDS_NORMr  search_queryr   r  r  r  r  rW  r  r  r  r  fetchallrG  )9rw  r  queryr  r  r  r  force_related_person_loginr  r  rO  r  r  r  r  r  r  r  r  r  r  r  r  r  r  rR  r[  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  query_token_listr  r  r  r  r  r  rE  rF  r  s9                                                            rJ  search_once_top_bm25z"CmfFullSearch.search_once_top_bm25  s    &:):
^++[z[[cghhhh*j**,
,,:#:#:'N&111 	*  	*  	*D ,<+;E=+Q+Q(
Iy !$ # # 	b!lN!l!l!l%aN%a%a%a" 	` j> j j j$_>$_$_$_! 	` j> j j j$_>$_$_$_! "$ 	cV%6%<%<S%A%A!B!Ba!G!G},, *M&&)b,)b)b)b& 	!EELE'++K>>	!.223EFF!.223EtLL -112CTJJ)--mTBB#0445IJJ"/334GHH?.)--m<< (,,\4@@
)--mZHH.;
#6j|  E?FFuzzRdGeGefff  CE#&#9#9&/#J#J [% 	%(%L%LMg%h%h"J

 $$%;<< 	%(%L%LVM`MdMde{M|M|%}%}"J

JJ1X
!HuQx'	 	[(mm8ZhZZZ
 J rvje<<BBDDEE  %zz*:SA]=^=^*^__$zz*:SA]=^=^*^__"5#7    $# 	Q$)JJv/G/M/M/O/O$P$P!H HP QX XR #5(,!2,&!2$"4!2!2&<%:%:&<
 
QX Xt!
&(; !
5!
#f&B!
 "#6!
 #$8	!

 &'>!
 '(@!
 *!
 !
 U=11!
 U!
 $%:%Bd!
 &+3t!
 V08D!
 f3!
 *!
  !!
" %& 0 0.&"4!2 &$""=!
 !
 !
> ?!
@ A!
F ),8@@BBJJ3PVWW``bb
 JrL  related_user
str | Noner  c                 ,   |p|j         }|j                            d          }	|j                            d          }
|j                            d          }|j                            d          }|j                            d          }|j                            d          }|j                            d          }|j                            d          }|j                            d	d           }|j                            d
|          }|p|}|j        }|r(d                    d                    |                    nd}|                     |j                  \  }}|r|                     |          \  }}nO|j                            d          r1|                     |j                            d                    \  }}nd}i }d}|rt          d           |x}}d}|t          vrt          d| d           d| }|j        sd}d}n(|j        d         }|j        d         |j        d         z
  }d}|rt          |          }d| d}|dk    rdnd}d| d| d| d | d!| d"| d"| d"| d#}t          j        j        j                                                            |i d$|d%|d&t'          |          d'|d(|d|	d	|d
|d|
d|d|d|d|d|d)|j        d*|j        d|||          }t-          |          } | S )+Nr[  r  r  r  r  r  r  r  r  r  r  r  r  r  z
            AND ( :responsible_name IS NULL OR obj_responsible_names ILIKE '%' || :responsible_name || '%' )
            AND ( :owner_name IS NULL OR obj_owner_name = :owner_name )
        z:Param related_user is deprecated. Use related_person_loginz
            AND (
                :responsible_name IS NULL
                OR obj_responsible_names ILIKE '%' || :responsible_name || '%'
                OR obj_owner_name = :owner_name
            )
        r  Tr;  r  r   r{  r  r  r  r0  r  a  
            SELECT
                obj_id,
                obj_code,
                obj_model,
                obj_name as title,
                obj_breadcrumbs as breadcrumbs,
                :label || (CASE WHEN EXTRACT(DAYS FROM (NOW() - obj_modified_at)) < 365 then 'R' else '' end) as label,
                100 / (EXTRACT(DAYS FROM (NOW() - obj_modified_at)) + 1) as rank,
                EXTRACT(DAYS FROM (NOW() - obj_modified_at)) as age_days,
                 as ,
                substring(` FROM 0 FOR 240) as headline
            FROM cmf_full_search
            WHERE
                a]  
                obj_model IN :model_name_in
                AND part_no <= :max_partno
                AND ( :parent_id IS NULL OR obj_parent_id = :parent_id )
                AND ( :author_name IS NULL OR obj_author_name = :author_name )
                AND ( :modified_by_name IS NULL OR obj_modified_by_name = :modified_by_name)
                z
                a  
                AND ( :logic_type_code IS NULL OR obj_logic_type_code = :logic_type_code )
                AND ( :status_type IS NULL OR obj_status_type = :status_type )
                AND ( :modified_at_before IS NULL OR obj_modified_at <= :modified_at_before )
                AND ( :modified_at_after IS NULL OR obj_modified_at >= :modified_at_after )
                AND ( :archived IS NULL OR obj_archived = :archived )
                AND ( :deleted IS NULL OR obj_deleted = :deleted )
                and ( :user_rating is null or obj_user_rating >= :user_rating)
                AND obj_modified_at is not null
            ORDER BY obj_modified_at DESC
            LIMIT :slice_for OFFSET :slice_from;
        r  r  r  r  r  r  r  )rO  r  r  r  r  r  r  r  r  r  r  fullsearch_slicerP  r  rW  r  r  r  r  r  r  r  rG  )!rw  r  r  r  r  r  r  r  rO  r[  r  r  r  r  r  r  r  r  r  r  r  r  r  r  owner_and_responsible_filterr  r  r  r  r  rE  r  all_objss!                                    rJ  filter_oncezCmfFullSearch.filter_once  s    &:):
'++K88	!.223EFF!.223EFF -112CDD)--m<<#0445IJJ"/334GHH)--m<<(,,\4@@
)--mZHH.;
#6j|  E?FFuzzRdGeGefff  CE#&#9#9&/#J#J [% 	%(%L%LMg%h%h"J

 $$%;<< 	%(%L%LVM`MdMde{M|M|%}%}"J

JJ($  		RSSS,88J),( ^++[z[[cghhhh*j**& 	PJII03J/2V5LQ5OOI 	\8}}H [x [ [ [ *f 4 4WW!
" " " $0" " (" " #" "( .)" "* +" ", -" ". $/" " "H ),8@@BBJJ3 Q
*Q
Q
 U=11Q
 U	Q

 *Q
 Q
 *Q
 ;Q
  0Q
  0Q
 Q
 ;Q
 !"4Q
  !2Q
 Q
  v~!Q
" ;#Q
$ %Q
& 'Q
  
* 
##rL  c                 >   t          t          j        j                  }|                     |          \  }}d}d}|rt          |          }d| d}d}d}d}	d}
d                    g d	| d
| d| d| d| d| d
| d| d| d| d| d
| d| d| d| d          }t          j        j	        j
                                                            ||	|
|d|                                          }t          |          S )Nr     r  r  EMTr	  r   r  a  
            (SELECT
                obj_id,
                obj_code,
                obj_model,
                obj_name as title,
                obj_breadcrumbs as breadcrumbs,
                :label || (CASE WHEN EXTRACT(DAYS FROM (NOW() - obj_modified_at)) < 365 then 'R' else '' end) as label,
                100 / (EXTRACT(DAYS FROM (NOW() - obj_modified_at)) + 1) as rank,
                EXTRACT(DAYS FROM (NOW() - obj_modified_at)) as age_days,
                r  r  r  zW
                obj_model = 'CmfTask' AND
                part_no = 0
                u  
                AND obj_modified_at is not null /* Временный хак пока не поправят багу TEM-1625047513 */
            ORDER BY obj_modified_at DESC
            LIMIT :slice_for OFFSET :slice_from)
            UNION
            (SELECT
                obj_id,
                obj_code,
                obj_model,
                obj_name as title,
                obj_breadcrumbs as breadcrumbs,
                :label || (CASE WHEN EXTRACT(DAYS FROM (NOW() - obj_modified_at)) < 365 then 'R' else '' end) as label,
                100 / (EXTRACT(DAYS FROM (NOW() - obj_modified_at)) + 1) as rank,
                EXTRACT(DAYS FROM (NOW() - obj_modified_at)) as age_days,
                z[
                obj_model = 'CmfDocument' AND
                part_no = 0
                z
                obj_model != 'CmfDocument' AND
                obj_model != 'CmfTask' AND
                part_no = 0
                u   
                AND obj_modified_at is not null /* Временный хак пока не поправят багу TEM-1625047513 */
            ORDER BY obj_modified_at DESC
            LIMIT :slice_for OFFSET :slice_from);
            )r  r  r  )rC  r  current_userrc  r  rP  r  r  rW  r  r  r  r  r	  rG  )rw  r  r  r  r  r  r  r  r  r  r  rE  r  s                rJ  filter_empty_topzCmfFullSearch.filter_empty_top  s    !566!$!H!HI]!^!^
J 	\8}}H [x [ [ [$
	@ @ @ @ @ @ @ @ @ @ $0@ @ @ @ (@ @ @ @ #@ @ @ @" #@ @ @ @> ?@ @ @ @> $0?@ @ @ @@ (A@ @ @ @F #G@ @ @ @L M@ @ @ @h i@ @ @ @h $0i@ @ @ @j (k@ @ @ @p #q@ @ @ @x y@ @ @ @ @ @D ),8@@BBJJ3$"Q
 Q
 	Q
  
 8:: 	 JrL  
tags_names	list[str]returntuple[str, dict[str, str]]c                 f    i }d}| r(d}dd                     d | D                        d|d<   ||fS )Nr  z AND obj_tags ~* :tags_re(^| |,)(|c              3   >   K   | ]}t          j        |          V  d S r  rR  escape)r~  r  s     rJ  r  z3CmfFullSearch._build_tags_filter.<locals>.<genexpr>  s-      8h8hQY89L9L8h8h8h8h8h8hrL  )( |,|$)tags_re)r  )r  r  r  s      rJ  r  z CmfFullSearch._build_tags_filter  sX      	s6K%r8h8h]g8h8h8h0h0h%r%r%rK	"K''rL  
user_loginrC  c                 T    i }d}| rd}t          j        |           } d|  d|d<   ||fS )Nr  z; AND obj_related_person_logins ~* :related_person_logins_rer"  r'  related_person_logins_rer%  )r)  r  r  s      rJ  r  z1CmfFullSearch._build_related_person_logins_filter  sL     

 	UVJ:..J5T
5T5T5TJ12:%%rL  c                 |   t          |           dk     rd S g }|d d         D ]}|d                             d          s|d                             d          s9i }|d         |d<   |                    dd           r|d         d         |d<   nd |d<   |                    |           t                                          }||_        d	|_        | |_        t          j
        j        |_        d
|_        t                                          5  |                                 d d d            d S # 1 swxY w Y   d S )Nr  r  r  zCmfDocument:zCmfTask:r  parentr]  r  F)r  
startswithr  r  r  CmfSearchStatrf  actionr  r  r  r  	person_id
aggregatedrZ  disable_aclsave)r  obj_dictst_dictrecst_recstats         rJ  _do_calc_statisticsz!CmfFullSearch._do_calc_statistics  s    |q  FCRC= 	# 	#CI((88 CI<P<PQ[<\<\ F"4yF8wwx&& ,'*8}T':|$$'+|$NN6""""##%%(*  "" 	 	IIKKK	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   D11D58D5)Fr  )FFr  )F)!NNNr  NNNNNFFNNNNNNNNNNNNNNNNNNNNFF)Nr{  F)FF)NNr  NFNr  )NNr  NNFN)NNNNr  N)r  r  r  r  )r  r  r  r   )r)  rC  r  r   )*__name__
__module____qualname____doc__rI  rM  	api_allowapi_methodsclassmethodry  r  r  r  r  r  r  r  r  r  r3  r  r  r  rV  r  	BaseModelrP  rg  staticmethodcmf_deferred_jobrn  ro  r  rm  r  r  r  r  r  r  r  r:  r}  rL  rJ  rW  rW  Z   s         K  O I  K, l l [l   [$ Q Q [Q p p [p   [ :F :F :F [:Fx g g g [g . . . [.   [<   [8  ' !"""&!#M~ ~ ~ [~@   [&   [$ _ _ [_B 	cj&: 	 	 	 [	 l l l [lB %%%; ; ; &% \;| 	
 	
 [	
 VWXXX]= ]= YX \]=@ X X [X e e \e Y[JLn  n  n  [n ^ SU`dr  r  r  [r j  &*37E #E %1	E E E [EP X  X  [X t ( ( ( \( & & & \&     \  rL  rW  )NN).r  r  mathcollectionsr   typingr   r   r   r   dataclassesr   r	   r
   r  sys	itertoolsr  cmf.data_providers.sqlalchemyr   cmf.fields.cmf_full_searchrV  cmf.models.cmf_search_engineenchantstring	pymorphy3rR  r  bs4r   MorphAnalyzermorphRUSSIAN_STOP_WORDSENGLISH_STOP_WORDSr  PROMPT_STOP_WORDS_NORMTECH_STOP_WORDSr  EVA_ARTIFACT_KEYS_STOP_WORDSEVA_ARTIFACT_VALUES_STOP_WORDSr  r  rK  rU  cmf_full_searchrW  r}  rL  rJ  <module>r[     s      " " " " " " , , , , , , , , , , , , 0 0 0 0 0 0 0 0 0 0         



         > > > > > > ! ! ! ! # # # #       				           	 	!! @  @  @  A  A  A 
  W   W   W    !\  !\  !\  \    !c  !c  !c  c   ,    !G  !G  !G  G  K  K  K :::"s#58J#JMi#il{#{  U  $U   V   V   M   M   M  "x  "x  "x  '*<<NOO___b b b b    { { { { {CJ.< { { { { {rL  