UNPKG

@langchain/community

Version:
1 lines • 5.43 kB
{"version":3,"file":"BM25.cjs","names":["corpus: string","term: string","documents: BMInputDocument<T>[]","keywords: string[]","constants?: BMConstants","sorter?: BMSorter<T>","b","keyword: string","a: number","b: number"],"sources":["../../../../src/utils/@furkantoprak/bm25/BM25.ts"],"sourcesContent":["/**\n * Adapted from\n * https://github.com/FurkanToprak/OkapiBM25\n *\n * Inlined due to CJS import issues.\n */\n\n/** Gets word count. */\nexport const getWordCount = (corpus: string) => {\n return ((corpus || \"\").match(/\\w+/g) || []).length;\n};\n\n/** Number of occurences of a word in a string. */\nexport const getTermFrequency = (term: string, corpus: string) => {\n // Escape any RegExp metacharacters in the term so constructing a RegExp\n // from user-provided or model-generated queries does not throw an error\n const escaped = (term || \"\").replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n return ((corpus || \"\").match(new RegExp(escaped, \"g\")) || []).length;\n};\n\n/** Inverse document frequency. */\nexport const getIDF = <T>(term: string, documents: BMInputDocument<T>[]) => {\n // Number of relevant documents.\n const relevantDocuments = documents.filter((document) =>\n document.text.includes(term)\n ).length;\n return Math.log(\n (documents.length - relevantDocuments + 0.5) / (relevantDocuments + 0.5) + 1\n );\n};\n\nexport interface BMInputDocument<T> {\n /** The text from the original document */\n text: string;\n /** The original document */\n document: T;\n}\n\n/** Represents a document; useful when sorting results.\n */\nexport interface BMOutputDocument<T> {\n /** The original document */\n document: T;\n /** The score that the document receives. */\n score: number;\n}\n\n/** Constants that are free parameters used in BM25, specifically when generating inverse document frequency. */\nexport interface BMConstants {\n /** Free parameter. Is 0.75 by default. */\n b?: number;\n /** Free parameter. Is 1.2 by default. Generally in range [1.2, 2.0] */\n k1?: number;\n}\n\n/** If returns positive, the sorting results in secondEl coming before firstEl, else, firstEl comes before secondEL */\nexport type BMSorter<T> = (\n firstEl: BMOutputDocument<T>,\n secondEl: BMOutputDocument<T>\n) => number;\n\n/** Implementation of Okapi BM25 algorithm.\n * @param documents: Collection of documents with text content and associated data.\n * @param keywords: query terms.\n * @param constants: Contains free parameters k1 and b. b=0.75 and k1=1.2 by default.\n * @param sorter: A function that allows you to sort results by a given rule. If not provided, returns results in the original document order.\n */\nexport function BM25<T>(\n documents: BMInputDocument<T>[],\n keywords: string[],\n constants?: BMConstants,\n sorter?: BMSorter<T>\n): BMOutputDocument<T>[] {\n const b = constants && constants.b ? constants.b : 0.75;\n const k1 = constants && constants.k1 ? constants.k1 : 1.2;\n const documentLengths = documents.map((document) =>\n getWordCount(document.text)\n );\n const averageDocumentLength =\n documentLengths.reduce((a, b) => a + b, 0) / documents.length;\n const idfByKeyword = keywords.reduce((obj, keyword) => {\n obj.set(keyword, getIDF(keyword, documents));\n return obj;\n }, new Map<string, number>());\n\n const scoredDocs = documents.map(({ text, document }, index) => {\n const score = keywords\n .map((keyword: string) => {\n const inverseDocumentFrequency = idfByKeyword.get(keyword);\n if (inverseDocumentFrequency === undefined) {\n throw new Error(\"Missing keyword.\");\n }\n const termFrequency = getTermFrequency(keyword, text);\n const documentLength = documentLengths[index];\n return (\n (inverseDocumentFrequency * (termFrequency * (k1 + 1))) /\n (termFrequency +\n k1 * (1 - b + (b * documentLength) / averageDocumentLength))\n );\n })\n .reduce((a: number, b: number) => a + b, 0);\n return { score, document } as BMOutputDocument<T>;\n });\n // sort the results\n if (sorter) {\n return scoredDocs.sort(sorter);\n }\n return scoredDocs;\n}\n"],"mappings":";;;;;;;;;AAQA,MAAa,eAAe,CAACA,WAAmB;AAC9C,UAAS,UAAU,IAAI,MAAM,OAAO,IAAI,CAAE,GAAE;AAC7C;;AAGD,MAAa,mBAAmB,CAACC,MAAcD,WAAmB;CAGhE,MAAM,WAAW,QAAQ,IAAI,QAAQ,uBAAuB,OAAO;AACnE,UAAS,UAAU,IAAI,MAAM,IAAI,OAAO,SAAS,KAAK,IAAI,CAAE,GAAE;AAC/D;;AAGD,MAAa,SAAS,CAAIC,MAAcC,cAAoC;CAE1E,MAAM,oBAAoB,UAAU,OAAO,CAAC,aAC1C,SAAS,KAAK,SAAS,KAAK,CAC7B,CAAC;AACF,QAAO,KAAK,KACT,UAAU,SAAS,oBAAoB,OAAQ,oBAAoB,MAAO,EAC5E;AACF;;;;;;;AAsCD,SAAgB,KACdA,WACAC,UACAC,WACAC,QACuB;CACvB,MAAM,IAAI,aAAa,UAAU,IAAI,UAAU,IAAI;CACnD,MAAM,KAAK,aAAa,UAAU,KAAK,UAAU,KAAK;CACtD,MAAM,kBAAkB,UAAU,IAAI,CAAC,aACrC,aAAa,SAAS,KAAK,CAC5B;CACD,MAAM,wBACJ,gBAAgB,OAAO,CAAC,GAAGC,QAAM,IAAIA,KAAG,EAAE,GAAG,UAAU;CACzD,MAAM,eAAe,SAAS,OAAO,CAAC,KAAK,YAAY;EACrD,IAAI,IAAI,SAAS,OAAO,SAAS,UAAU,CAAC;AAC5C,SAAO;CACR,mBAAE,IAAI,MAAsB;CAE7B,MAAM,aAAa,UAAU,IAAI,CAAC,EAAE,MAAM,UAAU,EAAE,UAAU;EAC9D,MAAM,QAAQ,SACX,IAAI,CAACC,YAAoB;GACxB,MAAM,2BAA2B,aAAa,IAAI,QAAQ;AAC1D,OAAI,6BAA6B,OAC/B,OAAM,IAAI,MAAM;GAElB,MAAM,gBAAgB,iBAAiB,SAAS,KAAK;GACrD,MAAM,iBAAiB,gBAAgB;AACvC,UACG,4BAA4B,iBAAiB,KAAK,OAClD,gBACC,MAAM,IAAI,IAAK,IAAI,iBAAkB;EAE1C,EAAC,CACD,OAAO,CAACC,GAAWC,QAAc,IAAIH,KAAG,EAAE;AAC7C,SAAO;GAAE;GAAO;EAAU;CAC3B,EAAC;AAEF,KAAI,OACF,QAAO,WAAW,KAAK,OAAO;AAEhC,QAAO;AACR"}