diff --git a/README.md b/README.md index 487260a..f5900aa 100644 --- a/README.md +++ b/README.md @@ -17,28 +17,13 @@ An enterprise-grade AI retriever designed to streamline AI integration into your -## 📝 Description - -Denser Retriever combines multiple search technologies into a single platform. It utilizes **gradient boosting ( -xgboost)** machine learning technique to combine: - -- **Keyword-based searches** that focus on fetching precisely what the query mentions. -- **Vector databases** that are great for finding a wide range of potentially relevant answers. -- **Machine Learning rerankers** that fine-tune the results to ensure the most relevant answers top the list. - -* Our experiments on MTEB datasets show that the combination of keyword search, vector search and a reranker via a xgboost model (denoted as ES+VS+RR_n) can significantly improve the vector search (VS) baseline. - -![mteb_ndcg_plot](https://github.com/denser-org/denser-retriever/blob/main/mteb_ndcg_plot.png?raw=true) - -* **Check out Denser Retriever experiments using the Anthropic Contextual Retrieval dataset at [here](https://github.com/denser-org/denser-retriever/tree/main/experiments/data/contextual-embeddings)**. ## 🚀 Features -The initial release of Denser Retriever provides the following features. - - Supporting heterogeneous retrievers such as **keyword search**, **vector search**, and **ML model reranking** - Leveraging **xgboost** ML technique to effectively combine heterogeneous retrievers -- **State-of-the-art accuracy** on [MTEB](https://github.com/embeddings-benchmark/mteb) Retrieval benchmarking +- **Comprehensive benchmark** on [MTEB](https://github.com/embeddings-benchmark/mteb) Retrieval dataset - Demonstrating how to use Denser retriever to power an **end-to-end applications** such as chatbot and semantic search +![mteb_ndcg_plot](https://github.com/denser-org/denser-retriever/blob/main/mteb_ndcg_plot.png?raw=true) ## 📦 Installation @@ -56,6 +41,14 @@ pip install denser-retriever poetry add denser-retriever ``` +## Quick Start + +## 📝 Experiments + +### [Anthropic Contextual Retrieval experiment](https://github.com/denser-org/denser-retriever/tree/main/experiments/data/contextual-embeddings) + +### [MTEB Retrieval experiment](https://retriever-docs.denser.ai/docs/core/experiments/mteb_retrieval) + ## 📃 Documentation The official documentation is hosted on [retriever.denser.ai](https://retriever.denser.ai). diff --git a/denser_retriever/embeddings.py b/denser_retriever/embeddings.py index abc8b15..9b6def4 100644 --- a/denser_retriever/embeddings.py +++ b/denser_retriever/embeddings.py @@ -40,6 +40,27 @@ def embed_query(self, text): return embeddings +class BGEEmbeddings(DenserEmbeddings): + def __init__(self, model_name: str, embedding_size: int): + try: + from FlagEmbedding import FlagICLModel + except ImportError as exc: + raise ImportError( + "Could not import FlagEmbedding python package." + ) from exc + + self.client = FlagICLModel(model_name, + query_instruction_for_retrieval="Given a web search query, retrieve relevant passages that answer the query.", + examples_for_task=None, # set `examples_for_task=None` to use model without examples + use_fp16=True) # Setting use_fp16 to True speeds up computation with a slight performance degradation + self.embedding_size = embedding_size + + def embed_documents(self, texts): + return self.client.encode_corpus(texts) + + def embed_query(self, text): + return self.client.encode_queries(text) + class VoyageAPIEmbeddings(DenserEmbeddings): def __init__(self, api_key: str, model_name: str, embedding_size: int): try: diff --git a/denser_retriever/keyword.py b/denser_retriever/keyword.py index c4af063..8b273cc 100644 --- a/denser_retriever/keyword.py +++ b/denser_retriever/keyword.py @@ -79,9 +79,6 @@ def retrieve( def get_index_mappings(self) -> Dict[Any, Any]: raise NotImplementedError - @abstractmethod - def get_categories(self, field: str, k: int = 10) -> List[Any]: - raise NotImplementedError @abstractmethod def delete( @@ -123,11 +120,12 @@ def __init__( self.analysis = analysis self.client = es_connection - def create_index(self, index_name: str, search_fields: List[str], **args: Any): + def create_index(self, index_name: str, search_fields: List[str], date_fields: List[str]=[], **args: Any): # Define the index settings and mappings self.index_name = index_name self.search_fields = FieldMapper(search_fields) + self.date_fields = date_fields logger.info("ES analysis %s", self.analysis) if self.analysis == "default": @@ -238,14 +236,15 @@ def add_documents( "source": metadata.get("source"), "pid": metadata.get("pid"), } - for filter in self.search_fields.get_keys(): - value = metadata.get(filter, "") + for filter_key in metadata.keys(): + value = metadata.get(filter_key, "") if isinstance(value, list): - value = [v.strip() for v in value] - elif value is not None: - value = value.strip() + value = [str(v).strip() for v in value if v is not None] + else: + if value is not None: + value = str(value).strip() if value: - request[filter] = value + request[filter_key] = value requests.append(request) if len(requests) > 0: @@ -271,37 +270,48 @@ def add_documents( return [] def retrieve( - self, - query: str, - k: int = 100, - filter: Dict[str, Any] = {}, - ) -> List[Tuple[Document, float]]: + self, + query: str, + k: int = 100, + filter: Dict[str, Any] = {}, + aggregation: bool = False, # Aggregate metadata + ) -> Tuple[List[Tuple[Document, float]], Dict]: assert self.client.indices.exists(index=self.index_name) start_time = time.time() + + # Build the query with title and content matching and a minimum_should_match condition query_dict = { "query": { "bool": { - "should": [ + "must": [ { - "match": { - "title": { - "query": query, - "boost": 2.0, - } + "bool": { + "should": [ + { + "match": { + "title": { + "query": query, + "boost": 2.0, + } + } + }, + { + "match": { + "content": query, + } + } + ], + "minimum_should_match": 1 # Ensure at least one of the should conditions is matched } - }, - { - "match": { - "content": query, - }, - }, - ], - "must": [], + } + ] } }, "_source": True, + "aggs": {}, # This will be populated with aggregations for fields } + # Add filters if provided for field in filter: category_or_date = filter.get(field) if category_or_date: @@ -313,7 +323,7 @@ def retrieve( "gte": category_or_date[0], "lte": category_or_date[1] if len(category_or_date) > 1 - else category_or_date[0], # type: ignore + else category_or_date[0], } } } @@ -323,32 +333,59 @@ def retrieve( {"term": {field: category_or_date}} ) + # Add aggregations for each field provided in 'fields' if aggregation is True + if aggregation: + for field in self.search_fields.get_keys(): + query_dict["aggs"][f"{field}_aggregation"] = { + "terms": { + "field": f"{field}", # Use keyword type for aggregations + "size": 50 # Adjust size as needed + } + } + + # Execute search query res = self.client.search( index=self.index_name, body=query_dict, size=k, ) + + # Process search hits (documents) top_k_used = min(len(res["hits"]["hits"]), k) docs = [] for id in range(top_k_used): _source = res["hits"]["hits"][id]["_source"] doc = Document( - page_content=_source["content"], - metadata={ - "source": _source["source"], - "title": _source["title"], - "pid": _source["pid"], - }, + page_content=_source.pop("content"), + metadata=_source, ) score = res["hits"]["hits"][id]["_score"] - for field in self.search_fields.get_keys(): - if _source.get(field): - doc.metadata[field] = _source.get(field) + # import pdb; pdb.set_trace() + # for field in self.search_fields.get_keys(): + # if _source.get(field): + # doc.metadata[field] = _source.get(field) docs.append((doc, score)) + + # Process aggregations for the specified fields + aggregations = {} + for field in self.search_fields.get_keys(): + field_agg = res.get("aggregations", {}).get(f"{field}_aggregation", {}).get("buckets", []) + cat_keys = [cat['key'] for cat in field_agg] + cat_counts = [cat['doc_count'] for cat in field_agg] + if len(cat_keys) > 0: + if field in self.date_fields: + sorted_data = sorted(zip(cat_keys, cat_counts), key=lambda x: x[0], reverse=True) + sorted_keys, sorted_counts = zip(*sorted_data) + cat_keys = list(sorted_keys) + cat_counts = list(sorted_counts) + aggregations[field] = (cat_keys, cat_counts) + retrieve_time_sec = time.time() - start_time logger.info(f"Keyword retrieve time: {retrieve_time_sec:.3f} sec.") logger.info(f"Retrieved {len(docs)} documents.") - return docs + + # Return both documents and aggregation results + return docs, aggregations def get_index_mappings(self): mapping = self.client.indices.get_mapping(index=self.index_name) @@ -377,25 +414,6 @@ def extract_fields(fields_dict, parent_name=""): all_fields = extract_fields(properties) return all_fields - def get_categories(self, field: str, k: int = 10): - query = { - "size": 0, # No actual documents are needed, just the aggregation results - "aggs": { - "all_categories": { - "terms": { - "field": field, - "size": 1000, # Adjust this value based on the expected number of unique categories - } - } - }, - } - response = self.client.search(index=self.index_name, body=query) - # Extract the aggregation results - categories = response["aggregations"]["all_categories"]["buckets"] - if k > 0: - categories = categories[:k] - res = [category["key"] for category in categories] - return res def delete( self, diff --git a/denser_retriever/retriever.py b/denser_retriever/retriever.py index ae30268..be94aa2 100644 --- a/denser_retriever/retriever.py +++ b/denser_retriever/retriever.py @@ -41,20 +41,22 @@ class RetrievalParams(BaseModel): vector_db: RetrievalConfig = RetrievalConfig() keyword: RetrievalConfig = RetrievalConfig() reranker: RetrievalConfig = RetrievalConfig(top_k=50) + aggregation: bool = False class DenserRetriever: def __init__( - self, - index_name: str, - keyword_search: Optional[DenserKeywordSearch], - vector_db: Optional[DenserVectorDB], - reranker: Optional[DenserReranker], - embeddings: DenserEmbeddings, - gradient_boost: Optional[DenserGradientBoost], - combine_mode: str = "linear", - xgb_model_features: str = "es+vs+rr_n", - search_fields: List[str] = [], + self, + index_name: str, + keyword_search: Optional[DenserKeywordSearch], + vector_db: Optional[DenserVectorDB], + reranker: Optional[DenserReranker], + embeddings: DenserEmbeddings, + gradient_boost: Optional[DenserGradientBoost], + combine_mode: str = "linear", + xgb_model_features: str = "es+vs+rr_n", + search_fields: List[str] = [], + date_fields: List[str] = [], ): # config parameters self.index_name = index_name @@ -73,7 +75,7 @@ def __init__( assert embeddings self.vector_db.create_index(index_name, embeddings, search_fields) if self.keyword_search: - self.keyword_search.create_index(index_name, search_fields) + self.keyword_search.create_index(index_name, search_fields, date_fields) def ingest(self, docs: List[Document], overwrite_pid: bool = True) -> List[str]: # add pid into metadata for each document @@ -92,12 +94,12 @@ def ingest(self, docs: List[Document], overwrite_pid: bool = True) -> List[str]: return [doc.metadata["pid"] for doc in docs] def retrieve( - self, - query: str, - k: int = 100, - filter: Dict[str, Any] = {}, - retrieval_params: RetrievalParams = RetrievalParams(), - **kwargs: Any, + self, + query: str, + k: int = 100, + filter: Dict[str, Any] = {}, + retrieval_params: RetrievalParams = RetrievalParams(), + **kwargs: Any, ): logger.info(f"Retrieve query: {query} top_k: {k}") if self.combine_mode in ["linear", "rank"]: @@ -108,18 +110,19 @@ def retrieve( return self._retrieve_by_model(query, k, filter, retrieval_params, **kwargs) def _retrieve_by_linear_or_rank( - self, - query: str, - k: int = 100, - filter: Dict[str, Any] = {}, - retrieval_params: RetrievalParams = RetrievalParams(), - **kwargs: Any, + self, + query: str, + k: int = 100, + filter: Dict[str, Any] = {}, + retrieval_params: RetrievalParams = RetrievalParams(), + **kwargs: Any, ): passages = [] + aggregations = None if self.keyword_search: - es_docs = self.keyword_search.retrieve( - query, retrieval_params.keyword.top_k, filter=filter, **kwargs + es_docs, aggregations = self.keyword_search.retrieve( + query, retrieval_params.keyword.top_k, filter=filter, aggregation=retrieval_params.aggregation, **kwargs ) es_passages = scale_results(es_docs, retrieval_params.keyword.weight) logger.info(f"Keyword search: {len(es_passages)}") @@ -153,15 +156,16 @@ def _retrieve_by_linear_or_rank( rerank_time_sec = time.time() - start_time logger.info(f"Rerank time: {rerank_time_sec:.3f} sec.") - return passages[:k] + return passages[:k], aggregations def _retrieve_by_model( - self, - query: str, - k: int = 100, - filter: Dict[str, Any] = {}, - retrieval_params: RetrievalParams = RetrievalParams(), - **kwargs: Any, + self, + query: str, + k: int = 100, + filter: Dict[str, Any] = {}, + retrieval_params: RetrievalParams = RetrievalParams(), + aggregation: bool = False, + **kwargs: Any, ) -> List[Tuple[Document, float]]: docs, doc_features = self._retrieve_with_features( query, filter, retrieval_params, **kwargs @@ -182,11 +186,11 @@ def _retrieve_by_model( return reranked_docs[:k] def _retrieve_with_features( - self, - query: str, - filter: Dict[str, Any] = {}, - retrieval_params: RetrievalParams = RetrievalParams(), - **kwargs: Any, + self, + query: str, + filter: Dict[str, Any] = {}, + retrieval_params: RetrievalParams = RetrievalParams(), + **kwargs: Any, ) -> Tuple[List[Document], List[List[str]]]: ks_docs = [] if self.keyword_search: @@ -288,10 +292,10 @@ def _retrieve_with_features( return docs, non_zero_normalized_features def delete( - self, - ids: Optional[List[str]] = None, - source_id: Optional[str] = None, - **kwargs: str, + self, + ids: Optional[List[str]] = None, + source_id: Optional[str] = None, + **kwargs: str, ): """Clear the retriever.""" if self.vector_db: @@ -306,21 +310,6 @@ def delete_all(self): if self.keyword_search: self.keyword_search.delete_all() - def get_field_categories(self, field, k: int = 10): - """ - Get the categories of a field. - - Args: - field: The field to get the categories of. - k: The number of categories to return. - - Returns: - A list of categories. - """ - if not self.keyword_search: - raise ValueError("Keyword search not initialized") - return self.keyword_search.get_categories(field, k) - def get_filter_fields(self): """Get the filter fields.""" if not self.keyword_search: diff --git a/denser_retriever/utils.py b/denser_retriever/utils.py index bae90fb..7e70c76 100644 --- a/denser_retriever/utils.py +++ b/denser_retriever/utils.py @@ -44,6 +44,7 @@ def evaluate( evaluator = pytrec_eval.RelevanceEvaluator( qrels, {map_string, ndcg_string, recall_string, precision_string} ) + # evaluator = None scores = evaluator.evaluate(results) for query_id in scores.keys(): diff --git a/denser_retriever/vectordb/milvus.py b/denser_retriever/vectordb/milvus.py index d579775..874aea4 100644 --- a/denser_retriever/vectordb/milvus.py +++ b/denser_retriever/vectordb/milvus.py @@ -109,7 +109,7 @@ def create_index( self.embeddings = embeddings self.source_max_length = 500 self.title_max_length = 500 - self.text_max_length = 8000 + self.text_max_length = 30000 self.field_max_length = 500 self.connection_args = self.connection_args or DEFAULT_MILVUS_CONNECTION @@ -207,7 +207,10 @@ def add_documents( doc.metadata.get("source", "")[: self.source_max_length - 10] ) titles.append(doc.metadata.get("title", "")[: self.title_max_length - 10]) - texts.append(doc.page_content[: self.text_max_length - 1000]) # buffer + truncated_text = doc.page_content[:10000] + if len(truncated_text) >= self.text_max_length: + print(f"Truncated text length: {len(truncated_text)} longer than {self.text_max_length}") + texts.append(truncated_text) pid_list.append(doc.metadata.get("pid", "-1")) for i, field_original_key in enumerate( diff --git a/examples/denser_search.py b/examples/denser_search.py index 6683261..b4c08f3 100644 --- a/examples/denser_search.py +++ b/examples/denser_search.py @@ -65,7 +65,8 @@ def denser_search(): format="MM.DD.YYYY", ) else: - categories = retriever.get_field_categories(field, 10) + # categories = retriever.get_field_categories(field, 10) + _, categories = retriever.retrieve("", 0, {}, True) ## TODO option = st.sidebar.selectbox( field, tuple(categories), diff --git a/examples/denser_search_cpws.py b/examples/denser_search_cpws.py deleted file mode 100644 index 76b9a79..0000000 --- a/examples/denser_search_cpws.py +++ /dev/null @@ -1,117 +0,0 @@ -import logging -import time -from datetime import date - -import streamlit as st -from langchain_community.document_loaders import CSVLoader -from langchain_text_splitters import RecursiveCharacterTextSplitter - -from denser_retriever.retriever import DenserRetriever - -logger = logging.getLogger(__name__) - -filter_fields = [ - "case_id:keyword", - "court:keyword", - "location:keyword", - "case_type:keyword", - "trial_procedure:keyword", - "trial_date:date", - "publication_date:date", - "cause:keyword", - "legal_basis:keyword", -] - -index_name = "unit_test_cpws" -retriever = DenserRetriever.from_milvus( - index_name, - milvus_uri="http://localhost:19530", - combine_mode="linear", - filter_fields=filter_fields, -) - -docs = CSVLoader( - "tests/test_data/cpws_2021_10_top10_en.csv", - metadata_columns=[ - "case_id", - "court", - "location", - "case_type", - "trial_procedure", - "trial_date", - "publication_date", - "cause", - "legal_basis", - ], -).load() -text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100) -texts = text_splitter.split_documents(docs) - -retriever.ingest(texts) - -starting_url = "https://wenshu.court.gov.cn/" -optional_str = 'Try questions such as "买卖合同纠纷"' - - -def denser_search(): - st.title("Denser Search Demo") - st.caption(f"Starting URL: {starting_url}") - if optional_str: - st.caption(f"{optional_str}") - st.divider() - - fields_and_types = retriever.get_filter_fields() - - meta_data = {} - for field, type in fields_and_types.items(): - if field in ["content", "title", "source", "pid"]: - continue - if type == "date": - option = st.sidebar.date_input( - field, - (date(1985, 1, 1), date(2021, 12, 31)), - date(1985, 1, 1), - date(2021, 12, 31), - format="MM.DD.YYYY", - ) - else: - categories = retriever.get_field_categories(field, 10) - option = st.sidebar.selectbox( - field, - tuple(categories), - index=None, - placeholder="Select ...", - ) - meta_data[field] = option - - if query := st.text_input("Input your query here", value=""): - st.write(f"Query: {query}") - st.write(f"Metadata: {meta_data}") - - start_time = time.time() - res = retriever.retrieve( - query, - filter=meta_data, - ) - docs = [doc for doc, _ in res] - retrieve_time_sec = time.time() - start_time - st.write(f"Retrieve time: {retrieve_time_sec:.3f} sec.") - - N_cards_per_row = 3 - chars_to_show = 80 - if docs: - for n_row, row in enumerate(docs): - i = n_row % N_cards_per_row - if i == 0: - st.write("---") - cols = st.columns(N_cards_per_row, gap="large") - # draw the card - with cols[n_row % N_cards_per_row]: - st.markdown(f"*{row.page_content[:chars_to_show].strip()}*") - for field in meta_data: - st.markdown(f"*{field}: {row.metadata.get(field)}*") - st.markdown(f"**{row.metadata['source']}**") - - -if __name__ == "__main__": - denser_search() diff --git a/experiments/train_and_test.py b/experiments/train_and_test.py index 708e809..64b00b3 100644 --- a/experiments/train_and_test.py +++ b/experiments/train_and_test.py @@ -3,6 +3,8 @@ import sys import json import shutil +import pickle +import time from langchain_core.documents import Document import xgboost as xgb @@ -14,16 +16,17 @@ ElasticKeywordSearch, create_elasticsearch_client, ) -from denser_retriever.reranker import HFReranker +from denser_retriever.reranker import HFReranker, CohereReranker from denser_retriever.retriever import DenserRetriever from denser_retriever.vectordb.milvus import MilvusDenserVectorDB -from denser_retriever.embeddings import VoyageAPIEmbeddings +from denser_retriever.embeddings import SentenceTransformerEmbeddings, VoyageAPIEmbeddings, BGEEmbeddings from experiments.hf_data_loader import HFDataLoader from experiments.denser_data import DenserData from denser_retriever.utils import ( evaluate, save_queries, save_qrels, + save_qrels_from_trec, load_qrels, docs_to_dict, ) @@ -53,20 +56,36 @@ def __init__(self, dataset_name, drop_old): self.retriever = DenserRetriever( index_name=index_name, keyword_search=ElasticKeywordSearch( - top_k=100, es_connection=create_elasticsearch_client(url="http://localhost:9200"), - drop_old=drop_old + drop_old=drop_old, + analysis="default" # default or ik ), vector_db=MilvusDenserVectorDB( - top_k=100, connection_args={"uri": "http://localhost:19530"}, auto_id=True, drop_old=drop_old ), - reranker=HFReranker(model_name="jinaai/jina-reranker-v2-base-multilingual", top_k=100, - automodel_args={"torch_dtype": "float32"}, trust_remote_code=True), - embeddings=VoyageAPIEmbeddings(api_key="YOUR_API_KEY", - model_name="voyage-2", embedding_size=1024), + reranker=HFReranker(model_name="cross-encoder/ms-marco-MiniLM-L-6-v2"), + embeddings=SentenceTransformerEmbeddings( + "Snowflake/snowflake-arctic-embed-m", 768, False + ), + # reranker=HFReranker(model_name="cross-encoder/ms-marco-MiniLM-L-6-v2", top_k=100), + # reranker=HFReranker(model_name="BAAI/bge-reranker-base", top_k=80), + # reranker=HFReranker(model_name="BAAI/bge-reranker-large", top_k=100), + + # embeddings=SentenceTransformerEmbeddings( + # "Snowflake/snowflake-arctic-embed-m", 768, False + # ), + # embeddings=VoyageAPIEmbeddings(api_key="pa-b76ti3S2pWuSl0go1S7f8-x150YAXUoh6UANO2LpHbI", model_name="voyage-2", embedding_size=1024), + # embeddings=VoyageAPIEmbeddings(api_key="pa-b76ti3S2pWuSl0go1S7f8-x150YAXUoh6UANO2LpHbI", model_name="voyage-law-2", embedding_size=1024), + # embeddings=SentenceTransformerEmbeddings( + # "chestnutlzj/ChatLaw-Text2Vec", 768, True + # ), + # embeddings=SentenceTransformerEmbeddings( + # "TencentBAC/Conan-embedding-v1", 1792, True + # ), + # embeddings=BGEEmbeddings(model_name="BAAI/bge-en-icl", embedding_size=4096), + # embeddings=None, gradient_boost=None ) @@ -74,6 +93,7 @@ def __init__(self, dataset_name, drop_old): self.max_query_len = 2000 self.max_doc_size = 0 self.max_doc_len = 8000 + self.top_k = 100 def ingest(self, dataset_name, split): exp_dir = os.path.join(self.output_prefix, split) @@ -85,8 +105,7 @@ def ingest(self, dataset_name, split): copy_file('experiments/data/contextual-embeddings/data_base/passages.jsonl', passage_file, self.max_doc_size) elif dataset_name == 'anthropic_context': - copy_file('experiments/data/contextual-embeddings/data_context/passages.jsonl', passage_file, - self.max_doc_size) + copy_file('experiments/data/contextual-embeddings/data_context/passages.jsonl', passage_file, self.max_doc_size) else: corpus, _, _ = HFDataLoader( hf_repo=dataset_name, @@ -96,7 +115,7 @@ def ingest(self, dataset_name, split): ).load(split=split) save_HF_corpus_as_docs( - corpus, passage_file, self.max_doc_size + corpus, passage_file, self.max_doc_size, self.max_doc_len ) out = open(passage_file, "r") @@ -143,12 +162,15 @@ def generate_feature_data(self, dataset_name, split): if (self.max_query_size > 0 and i >= self.max_query_size): break logger.info(f"Processing query {i}") + query_str = q["text"] + if (self.max_query_len > 0 and len(query_str) > self.max_query_len): + query_str = query_str[:self.max_query_len] qid = q["id"] - ks_docs = self.retriever.keyword_search.retrieve( - q["text"], self.retriever.keyword_search.top_k) + ks_docs, ks_aggregations = self.retriever.keyword_search.retrieve( + query_str, self.top_k) vs_docs = self.retriever.vector_db.similarity_search_with_score( - q["text"], self.retriever.vector_db.top_k) + query_str, self.top_k) combined = [] seen = set() @@ -161,7 +183,7 @@ def generate_feature_data(self, dataset_name, split): reranked_docs = [] # import pdb; pdb.set_trace() if self.retriever.reranker: - reranked_docs = self.retriever.reranker.rerank(combined_docs, q["text"]) + reranked_docs = self.retriever.reranker.rerank(combined_docs, query_str) _, ks_score_dict, ks_rank_dict = docs_to_dict(ks_docs) @@ -514,14 +536,14 @@ def report(self, eval_on, metric_str): dataset_name = sys.argv[1] train_on = sys.argv[2] eval_on = sys.argv[3] - drop_old = True + drop_old = False experiment = Experiment(dataset_name, drop_old) if drop_old: experiment.ingest(dataset_name, train_on) # Generate retriever data, this takes time - experiment.generate_feature_data(dataset_name, train_on) - if eval_on != train_on: - experiment.generate_feature_data(dataset_name, eval_on) + # experiment.generate_feature_data(dataset_name, train_on) + # if eval_on != train_on: + # experiment.generate_feature_data(dataset_name, eval_on) experiment.compute_baselines(eval_on) if train_on == eval_on: experiment.cross_validation(eval_on) @@ -531,5 +553,5 @@ def report(self, eval_on, metric_str): logger.info( f"train: {train_on}, eval: {eval_on}, cross-validation: {train_on == eval_on}" ) - experiment.report(eval_on, "NDCG@20") - experiment.report(eval_on, "Recall@20") + experiment.report(eval_on, "NDCG@10") + experiment.report(eval_on, "Recall@10") diff --git a/experiments/utils.py b/experiments/utils.py index a8b6fca..326931c 100644 --- a/experiments/utils.py +++ b/experiments/utils.py @@ -21,13 +21,15 @@ def copy_file(source_file, dest_file, top_k): else: break -def save_HF_corpus_as_docs(corpus, output_file: str, max_doc_size): +def save_HF_corpus_as_docs(corpus, output_file: str, max_doc_size, max_doc_len): out = open(output_file, "w") seen = set() for i, d in enumerate(corpus): if max_doc_size > 0 and i >= max_doc_size: break page_content = d.pop("text") + if max_doc_len > 0 and len(page_content) > max_doc_len: + page_content = page_content[:max_doc_len] d["pid"] = d.pop("id") assert d["pid"] not in seen seen.add(d["pid"]) diff --git a/tests/test_cpws.py b/tests/test_cpws.py deleted file mode 100644 index cf6ba95..0000000 --- a/tests/test_cpws.py +++ /dev/null @@ -1,54 +0,0 @@ -import pytest -from langchain_community.document_loaders.csv_loader import CSVLoader -from denser_retriever.embeddings import SentenceTransformerEmbeddings -from langchain_text_splitters import RecursiveCharacterTextSplitter - -from denser_retriever.retriever import DenserRetriever -from tests.utils import elasticsearch, milvus, reranker - - -# TODO: need rewrite -class TestCPWS: - def setup_method(self): - index_name = "unit_test_cpws" - - self.denser_retriever = DenserRetriever( - index_name=index_name, - vector_db=milvus, - keyword_search=elasticsearch, - reranker=reranker, - gradient_boost=None, - embeddings=SentenceTransformerEmbeddings( - "sentence-transformers/all-MiniLM-L6-v2", 384, True - ), - combine_mode="linear", - ) - - @pytest.fixture(autouse=True) - def titanic_data(self): - docs = CSVLoader( - "tests/test_data/cpws_2021_10_top10_en.csv", - ).load() - text_splitter = RecursiveCharacterTextSplitter( - chunk_size=500, chunk_overlap=100 - ) - - texts = text_splitter.split_documents(docs) - return texts - - def test_ingest(self, titanic_data): - ids = self.denser_retriever.ingest(titanic_data) - assert len(ids) == 25 - - def test_retrieve(self, titanic_data): - self.denser_retriever.ingest(titanic_data) - query = "Cumings" - filter = {"Sex": "female"} - k = 2 - results = self.denser_retriever.retrieve(query, k, filter=filter) - assert len(results) == k - assert abs(results[0][1] - 3.6725) < 0.01 - - def cleanup(self): - self.denser_retriever.vector_db.delete_all() - self.denser_retriever.keyword_search.delete_all() diff --git a/tests/test_data/cpws_2021_10_top10.csv b/tests/test_data/cpws_2021_10_top10.csv deleted file mode 100644 index 71737a6..0000000 --- a/tests/test_data/cpws_2021_10_top10.csv +++ /dev/null @@ -1,10 +0,0 @@ -原始链接,案号,案件名称,法院,所属地区,案件类型,案件类型编码,来源,审理程序,裁判日期,公开日期,当事人,案由,法律依据,全文 -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=18e4dbdb13524e3b93afadb600a15151,(2021)黑7530执472号,赵文君、李建国等买卖合同纠纷首次执行执行通知书,黑龙江省诺敏河人民法院,黑龙江省,执行案件,2,www.macrodatas.cn,执行实施,2021-10-02,2021-10-03,赵文君;李建国;安亚君,买卖合同纠纷,,文书内容黑龙江省诺敏河人民法院结 案 通 知 书(2021)黑7530执472号李**、安亚君:关于你二人申请执行程希江、赵文君买卖合同纠纷一案,本案已执行完毕。根据最高人民法院《关于执行案件立案、结案问题的意见》第十五条之规定,本案做结案处理。特此通知。二〇二一年十月二日 微信公众号“马克 数据网” -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=f812ad83ce3e4ebab3ecadb90124f166,(2021)新2924执510号,新疆玉象胡杨化工有限公司、辛宽买卖合同纠纷执行实施执行裁定书,沙雅县人民法院,沙雅县,执行案件,2,www.macrodatas.cn,执行实施,2021-10-02,2021-10-06,新疆玉象胡杨化工有限公司;辛宽,买卖合同纠纷,最高人民法院关于适用《中华人民共和国民事诉讼法》的解释:第四百六十六条,新疆维吾尔自治区沙雅县人民法院执行裁定书(2021)新2924执510号申请执行人:新疆玉象胡杨化工有限公司,住所地新疆维吾尔自治区沙雅县循环经济工业园区。    委托代理人:张春媛,女,1992年11月22日出生,汉族,新疆玉象胡杨化工有限公司员工,住新疆维吾尔自治区沙雅县。    被执行人:辛宽,男,1989年11月11日出生,汉族,无固定职业,住新疆维吾尔自治区沙雅县。    申请执行人新疆玉象胡杨化工有限公司与被执行人辛宽买卖合同纠纷一案,本院作出的(2020)新2924民初513号民事调解书已发生法律效力。被执行人辛宽拒不履行生效法律文书所确定的付款义务,申请执行人新疆玉象胡杨化工有限公司于2021年4月8日向本院申请执行,要求被执行人辛宽给付申请执行人新疆玉象胡杨化工有限公司案款107210元。本案已执行标的12334.17元,未执行标的94875.83元。    执行过程中,双方当事人自愿达成执行和解协议,申请执行人新疆玉象胡杨化工有限公司向本院撤回强制执行申请。依据《最高人民法院关于适用〈中华人民共和国民事诉讼法〉的解释》第四百六十六条之规定,裁定如下:    终结(2021)新2924执510号案件的执行。    本裁定送达后立即生效。    审判长    吴江海审判员    艾力·吾买尔审判员    阿迪力·吐尔逊二〇二一年十月二日法官助理    龙莲书记员    魏东  马 克 数 据 网 -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=fe008f4c7c7b4d708b9dadb90124f1b1,(2021)新28民申15号,李海波、大庆筑安建工集团有限公司巴州分公司等李路林、巴州中新南化工有限公司民间借贷纠纷民事审判监督民事裁定书,新疆维吾尔自治区巴音郭楞蒙古自治州中级人民法院,,民事案件,1,www.macrodatas.cn,民事审判监督,2021-10-04,2021-10-06,李海波;大庆筑安建工集团有限公司巴州分公司;李路林;巴州中新南化工有限公司,民间借贷纠纷,《中华人民共和国民事诉讼法》:第一百五十四条第一款第五项;最高人民法院关于适用《中华人民共和国民事诉讼法》的解释:第四百条第一款,新疆维吾尔自治区巴音郭楞蒙古自治州中级人民法院民事裁定书(2021)新28民申15号再审申请人(一审被告、二审上诉人):李海波,男,1953年5月27日出生,汉族,住湖南省长沙县。    被申请人(一审原告、二审被上诉人):大庆筑安建工集团有限公司巴州分公司,住所地新疆维吾尔自治区巴音郭楞蒙古自治州库尔勒市石化大道70号圣果名苑石榴园17栋1-102室二层。    主要负责人:王加兴,该公司经理。    被申请人(一审被告、二审被上诉人):李路林,男,1982年1月26日出生,汉族,住湖南省长沙县。    一审被告:巴州中新南化工有限公司,住所地新疆维吾尔自治区巴音郭楞蒙古自治州库尔勒市经济技术开发区友谊路南侧、巴州华洋石油技术服务有限公司用地东侧(坚宜佳公司内)。    法定代表人:李芳,该公司总经理。    原审第三人:龚哲明,男,1957年10月28日出生,汉族,住新疆维吾尔自治区巴音郭楞蒙古自治州库尔勒市。    再审申请人李海波因与被申请人大庆筑安建工集团有限公司巴州分公司、被申请人李路林、一审被告巴州中新南化工有限公司、原审第三人龚哲明民间借贷纠纷一案,不服新疆维吾尔自治区库尔勒市人民法院(2019)新2801民初47号民事判决,向本院申请再审。本院依法组成合议庭进行审查。    本院审查过程中,李海波于2021年9月27日提出撤回再审申请。    本院经审查认为,李海波撤回再审申请的请求,不违反法律规定,本院予以准许。    依照《中华人民共和国民事诉讼法》第一百五十四条第一款第五项,《最高人民法院关于适用〈中华人民共和国民事诉讼法〉的解释》第四百条第一款的规定,裁定如下:    准许李海波撤回再审申请。    审判长    徐胜兰审判员    杨春燕审判员    王嘉琦二〇二一年十月四日书记员    童凤娇  关注微信公众号“马克数据网” -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=14c07966328d46beba32adbb016ac8de,(2021)浙0726执恢925号,邵晨炳、黄坚宗等黄美娟借款合同纠纷执行实施类执行通知书,浦江县人民法院,浦江县,执行案件,2,www.macrodatas.cn,执行实施,2021-10-08,2021-10-08,邵晨炳;黄坚宗;黄美娟,借款合同纠纷,,浙江省浦江县人民法院结案通知书(2021)浙0726执恢925号本院执行的申请执行人邵晨炳与被执行人黄坚宗、黄美娟民间借贷纠纷一案,本院应执行(2017)浙0726民初2469号民事调解书确定的支付申请执行人101700元及利息,本院现已执行126167元,本案已执行完毕。二〇二一年十月八日联系人: 张卉 联系号码:88181216 来源:百度搜索“马克数据网” -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=15715fbf9a1b4d42ade0adbb010dd039,(2021)湘0281民初3143号,肖红、汪志坚离婚后财产纠纷民事一审民事裁定书,湖南省醴陵市人民法院,湖南省醴陵市,民事案件,1,www.macrodatas.cn,民事一审,2021-10-08,2021-10-08,肖红;汪志坚,离婚后财产纠纷,《中华人民共和国民事诉讼法》:第一百四十五条第一款;《中华人民共和国民事诉讼法》:第一百五十四条第一款第五项,湖南省醴陵市人民法院民 事 裁 定 书(2021)湘0281民初3143号原告:肖红。被告:汪志坚。本院在审理原告肖红与被告汪志坚离婚后财产纠纷一案中,原告肖红以双方达成和解为由,于2021年10月8日向本院提出撤诉申请。本院认为,原告自愿撤回起诉,不损害国家、集体和他人利益,不违反法律规定,依法应予准许。依照《中华人民共和国民事诉讼法》第一百四十五条第一款和第一百五十四条第一款第(五)项之规定,裁定如下:准许原告肖红撤回起诉。案件受理费100元,减半收取50元,由原告肖红负担。审 判 员 黄艳清二〇二一年十月八日法官助理 任 洋书 记 员 钟易丹附本案相关法律条文:《中华人民共和国民事诉讼法》第一百四十五条宣判前,原告申请撤诉的,是否准许,由人民法院裁定。人民法院裁定不准撤诉的,原告经传票传唤,无正当理由拒不到庭的,可以缺席判决。第一百五十四条裁定适用于下列范围:(一)不予受理;(二)对管辖权有异议的;(三)驳回起诉;(四)财产保全和先予执行;(五)准许或者不准许撤诉;(六)中止或者终结诉讼;(七)补正判决书中的笔误;(八)中止或者终结执行;(九)撤销或者不予执行仲裁裁决;(十)不予执行公证机关赋予强制执行效力的债权文(十一)其他需要裁定解决的事项。对前款第一项至第三项裁定,可以上诉。裁定书应当写明裁定结果和作出该裁定的理由。裁定书由审判人员、书记员署名,加盖人民法院印章。口头裁定的,记入笔录。 关注公众号“马 克 数 据 网” -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=163791656a7a43a69e71adbb01189421,(2021)浙0624执2655号,胡海锋、新昌县人民法院追缴违法所得执行实施类执行判决书,新昌县人民法院,新昌县,执行案件,2,www.macrodatas.cn,执行实施,2021-10-07,2021-10-08,胡海锋;新昌县人民法院,追缴违法所得,, 浙江省新昌县人民法院结 案 通 知 书(2021)浙0624执2655号 本院依据已经发生法律效力的(2014)绍新刑初字第字第408号刑事判决书,于2021年7月7日立案执行被执行人胡海锋赌博罪一案。执行中,经强制执行到位8500元,本案已全部执行完毕。特此通知。 二〇二一年十月七日 搜索“马 克 数 据 网” -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=140170e01ea749bb9b09adbb01189556,(2021)浙0624执2507号,唐仕荣、新昌县人民法院罚金执行实施类执行判决书,新昌县人民法院,新昌县,执行案件,2,www.macrodatas.cn,执行实施,2021-10-05,2021-10-08,唐仕荣;新昌县人民法院,罚金,最高人民法院关于适用《中华人民共和国刑事诉讼法》的解释:第五百二十九条第一款第五项;最高人民法院关于适用《中华人民共和国刑事诉讼法》的解释:第五百二十九条第二款, 浙江省新昌县人民法院 执行裁定书 (2021)浙0624执2507号 被执行人:唐仕荣,男,1967年01月05日出生(公民身份号码XXX),汉族,住所地贵州省纳雍县。 被执行人唐仕荣盗窃罪一案,本院作出的(2016)浙0624刑初568号刑事判决书已经发生法律效力。因被执行人未自觉履行判决书确定的义务,经本院刑事审判庭移送,本院于2021年6月17日立案执行。执行标的为支付罚金5000元及退赔被害人损失10060元。 执行立案后,本院于2021年06月18日向被执行人唐仕荣发出执行通知书、报告财产令和被执行人须知,要求被执行人履行生效法律文书确定的义务并报告财产情况,被执行人逾期未履行且未报告财产情况。 执行中,本院通过网络执行查控系统对被执行人唐仕荣的存款、不动产、车辆、有价证券等财产情况进行了查询,并委托被执行人户籍地所在地区的人民法院进行调查。查明,被执行人唐仕荣名下无不动产、银行存款、车辆和有价证券。截至2021年10月5日,本案执行标的已执行到位0元。暂未发现被执行人唐仕荣有其他可供执行的财产。 鉴于被执行人唐仕荣拒不履行又未报告财产,本院已对被执行人唐仕荣采取了纳入失信被执行人名单和限制消费的执行措施。 综上,被执行人唐仕荣暂无可供执行的财产,本案符合终结本次执行程序的条件。依照《最高人民法院关于适用〈中华人民共和国刑事诉讼法〉的解释》第五百二十九条第一款第五项、第二款规定,裁定如下: 终结本院(2021)浙0624执2507号案件本次执行程序。 裁定终结执行后,发现被执行人有可供执行财产,或者发现财产有被隐匿、转移等情形的,继续予以执行。 本裁定送达后立即生效。 审判长汤志刚 审判员王立 审判员章吉 二〇二一年十月五日 书记员唐浏冰 关注微信公众号“马克数据网” -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=172a5493562d439984fbadbb016ac4f4,(2021)浙0624执3030号,毛子明、浙江正坤建设集团有限公司劳动争议执行实施类执行调解书,新昌县人民法院,新昌县,执行案件,2,www.macrodatas.cn,执行实施,2021-10-08,2021-10-08,毛子明;浙江正坤建设集团有限公司,劳动争议,, 浙江省新昌县人民法院结 案 通 知 书(2021)浙0624执3030号 本院依据已经发生法律效力的浙新昌劳人仲案(2020)239号仲裁调解书,于2021年9月3日立案执行申请执行人毛子明与被执行人浙江正坤建设集团有限公司劳动争议仲裁一案。执行中,被执行人自动履行人民币30000元(其中案件执行标的金额30000元),本案已全部执行完毕。特此通知。 二〇二一年十月八日 百度搜索“马 克 数 据 网” -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=1d48f9faafa0441c81caadbb016ac924,(2021)浙0726执1671号,杨学珊、冯晨辉申请司法确认调解协议执行实施类执行裁定书,浦江县人民法院,浦江县,执行案件,2,www.macrodatas.cn,执行实施,2021-10-08,2021-10-08,杨学珊;冯晨辉,合同、无因管理、不当得利纠纷;民事,《中华人民共和国民事诉讼法》:第二百五十七条第六款, 浙江省浦江县人民法院 执行裁定书 (2021)浙0726执1671号 申请执行人:杨学珊(身份证号码XXX),女,1991年04月15日出生,住所地云南省临沧市临翔区。 被执行人:冯晨辉(身份证号码XXX),男,1989年01月24日出生,住所地浦江县。 本院在执行申请执行人杨学珊与被执行人冯晨辉(2021)浙0726执1671号申请司法确认调解协议一案中,(2021)浙0726民特381号已发生法律效力。申请执行人杨学珊于2021年4月16日向本院申请执行,本院于同日立案执行。在执行过程中,申请执行人杨学珊与被执行人冯晨辉自行沟通协商达成书面和解协议,经查系双方当事人真实意思表示,且系和解长期履行情形。依据《中华人民共和国民事诉讼法》第二百五十七条第六款之规定,裁定如下: 终结(2021)浙0726执1671号执行案件的执行。 本裁定书送达后立即生效。 本页无正文。 审判长黄明涛 审判员黄志远 审判员项凯丽 二〇二一年十月八日 代书记员张燏丰 更多数据:搜索“马克数据网”来源:www.macrodatas.cn diff --git a/tests/test_data/cpws_2021_10_top10_en.csv b/tests/test_data/cpws_2021_10_top10_en.csv deleted file mode 100644 index 92724bd..0000000 --- a/tests/test_data/cpws_2021_10_top10_en.csv +++ /dev/null @@ -1,10 +0,0 @@ -原始链接,case_id,案件名称,court,location,case_type,案件类型编码,来源,trial_procedure,trial_date,publication_date,当事人,cause,legal_basis,全文 -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=18e4dbdb13524e3b93afadb600a15151,(2021)黑7530执472号,赵文君、李建国等买卖合同纠纷首次执行执行通知书,黑龙江省诺敏河人民法院,黑龙江省,执行案件,2,www.macrodatas.cn,执行实施,2021-10-02,2021-10-03,赵文君;李建国;安亚君,买卖合同纠纷,,文书内容黑龙江省诺敏河人民法院结 案 通 知 书(2021)黑7530执472号李**、安亚君:关于你二人申请执行程希江、赵文君买卖合同纠纷一案,本案已执行完毕。根据最高人民法院《关于执行案件立案、结案问题的意见》第十五条之规定,本案做结案处理。特此通知。二〇二一年十月二日 微信公众号“马克 数据网” -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=f812ad83ce3e4ebab3ecadb90124f166,(2021)新2924执510号,新疆玉象胡杨化工有限公司、辛宽买卖合同纠纷执行实施执行裁定书,沙雅县人民法院,沙雅县,执行案件,2,www.macrodatas.cn,执行实施,2021-10-02,2021-10-06,新疆玉象胡杨化工有限公司;辛宽,买卖合同纠纷,最高人民法院关于适用《中华人民共和国民事诉讼法》的解释:第四百六十六条,新疆维吾尔自治区沙雅县人民法院执行裁定书(2021)新2924执510号申请执行人:新疆玉象胡杨化工有限公司,住所地新疆维吾尔自治区沙雅县循环经济工业园区。    委托代理人:张春媛,女,1992年11月22日出生,汉族,新疆玉象胡杨化工有限公司员工,住新疆维吾尔自治区沙雅县。    被执行人:辛宽,男,1989年11月11日出生,汉族,无固定职业,住新疆维吾尔自治区沙雅县。    申请执行人新疆玉象胡杨化工有限公司与被执行人辛宽买卖合同纠纷一案,本院作出的(2020)新2924民初513号民事调解书已发生法律效力。被执行人辛宽拒不履行生效法律文书所确定的付款义务,申请执行人新疆玉象胡杨化工有限公司于2021年4月8日向本院申请执行,要求被执行人辛宽给付申请执行人新疆玉象胡杨化工有限公司案款107210元。本案已执行标的12334.17元,未执行标的94875.83元。    执行过程中,双方当事人自愿达成执行和解协议,申请执行人新疆玉象胡杨化工有限公司向本院撤回强制执行申请。依据《最高人民法院关于适用〈中华人民共和国民事诉讼法〉的解释》第四百六十六条之规定,裁定如下:    终结(2021)新2924执510号案件的执行。    本裁定送达后立即生效。    审判长    吴江海审判员    艾力·吾买尔审判员    阿迪力·吐尔逊二〇二一年十月二日法官助理    龙莲书记员    魏东  马 克 数 据 网 -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=fe008f4c7c7b4d708b9dadb90124f1b1,(2021)新28民申15号,李海波、大庆筑安建工集团有限公司巴州分公司等李路林、巴州中新南化工有限公司民间借贷纠纷民事审判监督民事裁定书,新疆维吾尔自治区巴音郭楞蒙古自治州中级人民法院,,民事案件,1,www.macrodatas.cn,民事审判监督,2021-10-04,2021-10-06,李海波;大庆筑安建工集团有限公司巴州分公司;李路林;巴州中新南化工有限公司,民间借贷纠纷,《中华人民共和国民事诉讼法》:第一百五十四条第一款第五项;最高人民法院关于适用《中华人民共和国民事诉讼法》的解释:第四百条第一款,新疆维吾尔自治区巴音郭楞蒙古自治州中级人民法院民事裁定书(2021)新28民申15号再审申请人(一审被告、二审上诉人):李海波,男,1953年5月27日出生,汉族,住湖南省长沙县。    被申请人(一审原告、二审被上诉人):大庆筑安建工集团有限公司巴州分公司,住所地新疆维吾尔自治区巴音郭楞蒙古自治州库尔勒市石化大道70号圣果名苑石榴园17栋1-102室二层。    主要负责人:王加兴,该公司经理。    被申请人(一审被告、二审被上诉人):李路林,男,1982年1月26日出生,汉族,住湖南省长沙县。    一审被告:巴州中新南化工有限公司,住所地新疆维吾尔自治区巴音郭楞蒙古自治州库尔勒市经济技术开发区友谊路南侧、巴州华洋石油技术服务有限公司用地东侧(坚宜佳公司内)。    法定代表人:李芳,该公司总经理。    原审第三人:龚哲明,男,1957年10月28日出生,汉族,住新疆维吾尔自治区巴音郭楞蒙古自治州库尔勒市。    再审申请人李海波因与被申请人大庆筑安建工集团有限公司巴州分公司、被申请人李路林、一审被告巴州中新南化工有限公司、原审第三人龚哲明民间借贷纠纷一案,不服新疆维吾尔自治区库尔勒市人民法院(2019)新2801民初47号民事判决,向本院申请再审。本院依法组成合议庭进行审查。    本院审查过程中,李海波于2021年9月27日提出撤回再审申请。    本院经审查认为,李海波撤回再审申请的请求,不违反法律规定,本院予以准许。    依照《中华人民共和国民事诉讼法》第一百五十四条第一款第五项,《最高人民法院关于适用〈中华人民共和国民事诉讼法〉的解释》第四百条第一款的规定,裁定如下:    准许李海波撤回再审申请。    审判长    徐胜兰审判员    杨春燕审判员    王嘉琦二〇二一年十月四日书记员    童凤娇  关注微信公众号“马克数据网” -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=14c07966328d46beba32adbb016ac8de,(2021)浙0726执恢925号,邵晨炳、黄坚宗等黄美娟借款合同纠纷执行实施类执行通知书,浦江县人民法院,浦江县,执行案件,2,www.macrodatas.cn,执行实施,2021-10-08,2021-10-08,邵晨炳;黄坚宗;黄美娟,借款合同纠纷,,浙江省浦江县人民法院结案通知书(2021)浙0726执恢925号本院执行的申请执行人邵晨炳与被执行人黄坚宗、黄美娟民间借贷纠纷一案,本院应执行(2017)浙0726民初2469号民事调解书确定的支付申请执行人101700元及利息,本院现已执行126167元,本案已执行完毕。二〇二一年十月八日联系人: 张卉 联系号码:88181216 来源:百度搜索“马克数据网” -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=15715fbf9a1b4d42ade0adbb010dd039,(2021)湘0281民初3143号,肖红、汪志坚离婚后财产纠纷民事一审民事裁定书,湖南省醴陵市人民法院,湖南省醴陵市,民事案件,1,www.macrodatas.cn,民事一审,2021-10-08,2021-10-08,肖红;汪志坚,离婚后财产纠纷,《中华人民共和国民事诉讼法》:第一百四十五条第一款;《中华人民共和国民事诉讼法》:第一百五十四条第一款第五项,湖南省醴陵市人民法院民 事 裁 定 书(2021)湘0281民初3143号原告:肖红。被告:汪志坚。本院在审理原告肖红与被告汪志坚离婚后财产纠纷一案中,原告肖红以双方达成和解为由,于2021年10月8日向本院提出撤诉申请。本院认为,原告自愿撤回起诉,不损害国家、集体和他人利益,不违反法律规定,依法应予准许。依照《中华人民共和国民事诉讼法》第一百四十五条第一款和第一百五十四条第一款第(五)项之规定,裁定如下:准许原告肖红撤回起诉。案件受理费100元,减半收取50元,由原告肖红负担。审 判 员 黄艳清二〇二一年十月八日法官助理 任 洋书 记 员 钟易丹附本案相关法律条文:《中华人民共和国民事诉讼法》第一百四十五条宣判前,原告申请撤诉的,是否准许,由人民法院裁定。人民法院裁定不准撤诉的,原告经传票传唤,无正当理由拒不到庭的,可以缺席判决。第一百五十四条裁定适用于下列范围:(一)不予受理;(二)对管辖权有异议的;(三)驳回起诉;(四)财产保全和先予执行;(五)准许或者不准许撤诉;(六)中止或者终结诉讼;(七)补正判决书中的笔误;(八)中止或者终结执行;(九)撤销或者不予执行仲裁裁决;(十)不予执行公证机关赋予强制执行效力的债权文(十一)其他需要裁定解决的事项。对前款第一项至第三项裁定,可以上诉。裁定书应当写明裁定结果和作出该裁定的理由。裁定书由审判人员、书记员署名,加盖人民法院印章。口头裁定的,记入笔录。 关注公众号“马 克 数 据 网” -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=163791656a7a43a69e71adbb01189421,(2021)浙0624执2655号,胡海锋、新昌县人民法院追缴违法所得执行实施类执行判决书,新昌县人民法院,新昌县,执行案件,2,www.macrodatas.cn,执行实施,2021-10-07,2021-10-08,胡海锋;新昌县人民法院,追缴违法所得,, 浙江省新昌县人民法院结 案 通 知 书(2021)浙0624执2655号 本院依据已经发生法律效力的(2014)绍新刑初字第字第408号刑事判决书,于2021年7月7日立案执行被执行人胡海锋赌博罪一案。执行中,经强制执行到位8500元,本案已全部执行完毕。特此通知。 二〇二一年十月七日 搜索“马 克 数 据 网” -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=140170e01ea749bb9b09adbb01189556,(2021)浙0624执2507号,唐仕荣、新昌县人民法院罚金执行实施类执行判决书,新昌县人民法院,新昌县,执行案件,2,www.macrodatas.cn,执行实施,2021-10-05,2021-10-08,唐仕荣;新昌县人民法院,罚金,最高人民法院关于适用《中华人民共和国刑事诉讼法》的解释:第五百二十九条第一款第五项;最高人民法院关于适用《中华人民共和国刑事诉讼法》的解释:第五百二十九条第二款, 浙江省新昌县人民法院 执行裁定书 (2021)浙0624执2507号 被执行人:唐仕荣,男,1967年01月05日出生(公民身份号码XXX),汉族,住所地贵州省纳雍县。 被执行人唐仕荣盗窃罪一案,本院作出的(2016)浙0624刑初568号刑事判决书已经发生法律效力。因被执行人未自觉履行判决书确定的义务,经本院刑事审判庭移送,本院于2021年6月17日立案执行。执行标的为支付罚金5000元及退赔被害人损失10060元。 执行立案后,本院于2021年06月18日向被执行人唐仕荣发出执行通知书、报告财产令和被执行人须知,要求被执行人履行生效法律文书确定的义务并报告财产情况,被执行人逾期未履行且未报告财产情况。 执行中,本院通过网络执行查控系统对被执行人唐仕荣的存款、不动产、车辆、有价证券等财产情况进行了查询,并委托被执行人户籍地所在地区的人民法院进行调查。查明,被执行人唐仕荣名下无不动产、银行存款、车辆和有价证券。截至2021年10月5日,本案执行标的已执行到位0元。暂未发现被执行人唐仕荣有其他可供执行的财产。 鉴于被执行人唐仕荣拒不履行又未报告财产,本院已对被执行人唐仕荣采取了纳入失信被执行人名单和限制消费的执行措施。 综上,被执行人唐仕荣暂无可供执行的财产,本案符合终结本次执行程序的条件。依照《最高人民法院关于适用〈中华人民共和国刑事诉讼法〉的解释》第五百二十九条第一款第五项、第二款规定,裁定如下: 终结本院(2021)浙0624执2507号案件本次执行程序。 裁定终结执行后,发现被执行人有可供执行财产,或者发现财产有被隐匿、转移等情形的,继续予以执行。 本裁定送达后立即生效。 审判长汤志刚 审判员王立 审判员章吉 二〇二一年十月五日 书记员唐浏冰 关注微信公众号“马克数据网” -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=172a5493562d439984fbadbb016ac4f4,(2021)浙0624执3030号,毛子明、浙江正坤建设集团有限公司劳动争议执行实施类执行调解书,新昌县人民法院,新昌县,执行案件,2,www.macrodatas.cn,执行实施,2021-10-08,2021-10-08,毛子明;浙江正坤建设集团有限公司,劳动争议,, 浙江省新昌县人民法院结 案 通 知 书(2021)浙0624执3030号 本院依据已经发生法律效力的浙新昌劳人仲案(2020)239号仲裁调解书,于2021年9月3日立案执行申请执行人毛子明与被执行人浙江正坤建设集团有限公司劳动争议仲裁一案。执行中,被执行人自动履行人民币30000元(其中案件执行标的金额30000元),本案已全部执行完毕。特此通知。 二〇二一年十月八日 百度搜索“马 克 数 据 网” -https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=1d48f9faafa0441c81caadbb016ac924,(2021)浙0726执1671号,杨学珊、冯晨辉申请司法确认调解协议执行实施类执行裁定书,浦江县人民法院,浦江县,执行案件,2,www.macrodatas.cn,执行实施,2021-10-08,2021-10-08,杨学珊;冯晨辉,合同、无因管理、不当得利纠纷;民事,《中华人民共和国民事诉讼法》:第二百五十七条第六款, 浙江省浦江县人民法院 执行裁定书 (2021)浙0726执1671号 申请执行人:杨学珊(身份证号码XXX),女,1991年04月15日出生,住所地云南省临沧市临翔区。 被执行人:冯晨辉(身份证号码XXX),男,1989年01月24日出生,住所地浦江县。 本院在执行申请执行人杨学珊与被执行人冯晨辉(2021)浙0726执1671号申请司法确认调解协议一案中,(2021)浙0726民特381号已发生法律效力。申请执行人杨学珊于2021年4月16日向本院申请执行,本院于同日立案执行。在执行过程中,申请执行人杨学珊与被执行人冯晨辉自行沟通协商达成书面和解协议,经查系双方当事人真实意思表示,且系和解长期履行情形。依据《中华人民共和国民事诉讼法》第二百五十七条第六款之规定,裁定如下: 终结(2021)浙0726执1671号执行案件的执行。 本裁定书送达后立即生效。 本页无正文。 审判长黄明涛 审判员黄志远 审判员项凯丽 二〇二一年十月八日 代书记员张燏丰 更多数据:搜索“马克数据网”来源:www.macrodatas.cn diff --git a/tests/test_keyword.py b/tests/test_keyword.py index 5a33366..47c1e0d 100644 --- a/tests/test_keyword.py +++ b/tests/test_keyword.py @@ -39,7 +39,8 @@ def test_retrieve(self, keyword_search: DenserKeywordSearch): Document(page_content="content2", metadata={"title": "title2"}), ] keyword_search.add_documents(documents) - results = keyword_search.retrieve("content1", 1) + results, _ = keyword_search.retrieve("content1", 1) + # import pdb; pdb.set_trace() assert len(results) == 1 def test_get_index_mappings(self, keyword_search): @@ -47,6 +48,3 @@ def test_get_index_mappings(self, keyword_search): assert "field1" in mappings assert "field2" in mappings - def test_get_categories(self, keyword_search): - categories = keyword_search.get_categories("field2") - assert len(categories) == 0 diff --git a/tests/test_retriever.py b/tests/test_retriever.py index bfde61a..4d2c160 100644 --- a/tests/test_retriever.py +++ b/tests/test_retriever.py @@ -38,7 +38,7 @@ def test_retrieve(self): self.denser_retriever.ingest(docs) query = "content1" k = 2 - results = self.denser_retriever.retrieve(query, k) + results, _ = self.denser_retriever.retrieve(query, k) assert len(results) == k assert results[0][0].page_content == "content1" @@ -53,13 +53,6 @@ def test_get_field_categories(self): Document(page_content="content2", metadata={"title": "title2", "source": "source_test2"}), ] self.denser_retriever.ingest(docs) - field = "category_field" - k = 10 - categories = self.denser_retriever.get_field_categories(field, k) - assert isinstance(categories, list) - assert len(categories) <= k - for category in categories: - assert isinstance(category, str) def test_get_metadata_fields(self): docs = [ @@ -77,7 +70,7 @@ def test_delete_by_id(self): ] ids = self.denser_retriever.ingest(docs) self.denser_retriever.delete(ids=[ids[0]]) - results = self.denser_retriever.retrieve("content1", k=1) + results, _ = self.denser_retriever.retrieve("content1", k=1) assert len(results) == 1 def test_delete_all(self): @@ -96,7 +89,7 @@ def test_delete_by_source(self): ] self.denser_retriever.ingest(docs) self.denser_retriever.delete(source_id="source_test1") - results = self.denser_retriever.retrieve("content1", k=1) + results, _ = self.denser_retriever.retrieve("content1", k=1) # only content2 should be retrieved assert len(results) == 1 @@ -107,5 +100,5 @@ def test_delete_by_source_url(self): ] self.denser_retriever.ingest(docs) self.denser_retriever.delete(source_url="source_test1") - results = self.denser_retriever.retrieve("content1", k=1) + results, _ = self.denser_retriever.retrieve("content1", k=1) assert len(results) == 1 diff --git a/tests/test_titanic.py b/tests/test_titanic.py index e375de9..49b1dc6 100644 --- a/tests/test_titanic.py +++ b/tests/test_titanic.py @@ -3,7 +3,7 @@ from langchain_text_splitters import RecursiveCharacterTextSplitter from denser_retriever.embeddings import SentenceTransformerEmbeddings -from denser_retriever.retriever import DenserRetriever +from denser_retriever.retriever import DenserRetriever, RetrievalParams from tests.utils import milvus, reranker, elasticsearch @@ -69,5 +69,7 @@ def test_retrieve(self, titanic_data): query = "Cumings" k = 2 filter = {"Sex": "female"} - results = self.denser_retriever.retrieve(query, k, filter=filter) + retrieval_params = RetrievalParams(aggregation=True) + results, aggregations = self.denser_retriever.retrieve(query, k, filter=filter, retrieval_params=retrieval_params) + import pdb; pdb.set_trace() assert abs(results[0][1] - 3.6725) < 0.01 diff --git a/tests/test_utils.py b/tests/test_utils.py deleted file mode 100644 index a59df82..0000000 --- a/tests/test_utils.py +++ /dev/null @@ -1,37 +0,0 @@ -from typing import Any, Dict -from denser_retriever.filter import generate_milvus_expr - -def test_generate_milvus_expr_with_none_values() -> None: - filter_dict: Dict[str, Any] = { - "name": "John", - "age": None, - "city": None, - } - expected_expr = "name == 'John'" - assert generate_milvus_expr(filter_dict) == expected_expr - - -def test_generate_milvus_expr_with_range_values() -> None: - filter_dict: Dict[str, Any] = { - "price": (10, 100), - "rating": (4.5, 5.0), - } - expected_expr = ( - "price >= '10' and price <= '100' and rating >= '4.5' and rating <= '5.0'" - ) - assert generate_milvus_expr(filter_dict) == expected_expr - - -def test_generate_milvus_expr_with_single_value() -> None: - filter_dict: Dict[str, Any] = { - "category": "electronics", - "brand": "Apple", - } - expected_expr = "category == 'electronics' and brand == 'Apple'" - assert generate_milvus_expr(filter_dict) == expected_expr - - -def test_generate_milvus_expr_with_empty_dict() -> None: - filter_dict: Dict[str, Any] = {} - expected_expr = "" - assert generate_milvus_expr(filter_dict) == expected_expr diff --git a/utils/preprocess_data.py b/utils/preprocess_data.py deleted file mode 100644 index 8d8bd07..0000000 --- a/utils/preprocess_data.py +++ /dev/null @@ -1,39 +0,0 @@ -import csv -import json -import logging - -logger = logging.getLogger(__name__) - - -def csv_to_jsonl(csv_filepath, jsonl_filepath): - """ - Convert a CSV file to a JSON Lines (JSONL) file. - - Args: - csv_filepath (str): The path to the input CSV file. - jsonl_filepath (str): The path to the output JSONL file. - """ - key_update = {"原始链接": "source", "案件名称": "title", "全文": "text"} - with open(csv_filepath, mode="r", newline="", encoding="utf-8-sig") as csv_file: - csv_reader = csv.DictReader(csv_file) - - with open(jsonl_filepath, mode="w", newline="", encoding="utf-8") as jsonl_file: - # Convert each row to JSON and write it to the JSONL file - for item in csv_reader: - for key in key_update.keys(): - if key in item: - item[key_update[key]] = item.pop(key) - else: - item[key_update[key]] = "" - logger.info(f"Missing key {key} in {item}") - item["pid"] = -1 - if item["source"]: - jsonl_file.write(json.dumps(item, ensure_ascii=False) + "\n") - else: - logger.info(f"Skip {item}") - - -if __name__ == "__main__": - input_file = "tests/test_data/cpws_2021_10_top10.csv" - output_file = "tests/test_data/cpws_passages_top10.jsonl" - csv_to_jsonl(input_file, output_file) diff --git a/utils/preprocess_data_cpws.py b/utils/preprocess_data_cpws.py deleted file mode 100644 index 8d8bd07..0000000 --- a/utils/preprocess_data_cpws.py +++ /dev/null @@ -1,39 +0,0 @@ -import csv -import json -import logging - -logger = logging.getLogger(__name__) - - -def csv_to_jsonl(csv_filepath, jsonl_filepath): - """ - Convert a CSV file to a JSON Lines (JSONL) file. - - Args: - csv_filepath (str): The path to the input CSV file. - jsonl_filepath (str): The path to the output JSONL file. - """ - key_update = {"原始链接": "source", "案件名称": "title", "全文": "text"} - with open(csv_filepath, mode="r", newline="", encoding="utf-8-sig") as csv_file: - csv_reader = csv.DictReader(csv_file) - - with open(jsonl_filepath, mode="w", newline="", encoding="utf-8") as jsonl_file: - # Convert each row to JSON and write it to the JSONL file - for item in csv_reader: - for key in key_update.keys(): - if key in item: - item[key_update[key]] = item.pop(key) - else: - item[key_update[key]] = "" - logger.info(f"Missing key {key} in {item}") - item["pid"] = -1 - if item["source"]: - jsonl_file.write(json.dumps(item, ensure_ascii=False) + "\n") - else: - logger.info(f"Skip {item}") - - -if __name__ == "__main__": - input_file = "tests/test_data/cpws_2021_10_top10.csv" - output_file = "tests/test_data/cpws_passages_top10.jsonl" - csv_to_jsonl(input_file, output_file)